@mintjamsinc/ichigojs 0.1.78 → 0.1.80
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/README.md +12 -0
- package/dist/ichigo.cjs +152 -31
- package/dist/ichigo.cjs.map +1 -1
- package/dist/ichigo.esm.js +152 -31
- package/dist/ichigo.esm.js.map +1 -1
- package/dist/ichigo.esm.min.js +1 -1
- package/dist/ichigo.min.cjs +1 -1
- package/dist/ichigo.umd.js +152 -31
- package/dist/ichigo.umd.js.map +1 -1
- package/dist/ichigo.umd.min.js +1 -1
- package/dist/types/ichigo/VNode.d.ts +20 -0
- package/dist/types/ichigo/components/IchigoElement.d.ts +52 -0
- package/package.json +1 -1
package/dist/ichigo.esm.js
CHANGED
|
@@ -9218,8 +9218,9 @@ class VSlotOutletDirective {
|
|
|
9218
9218
|
this.#scopeBindings.setLocal(this.#entry.scopeVar, this.#buildSlotProps());
|
|
9219
9219
|
}
|
|
9220
9220
|
// Clone the scoped template's content and create its VNode tree BEFORE
|
|
9221
|
-
// inserting into the DOM, so
|
|
9222
|
-
//
|
|
9221
|
+
// inserting into the DOM, so its directives run against a subtree
|
|
9222
|
+
// nothing else can observe yet. Components inside are expanded
|
|
9223
|
+
// afterwards, once the content is in the document.
|
|
9223
9224
|
// (Created through the parent application to keep the VNode import
|
|
9224
9225
|
// type-only; a direct `new VNode` here would close a module cycle
|
|
9225
9226
|
// VNode -> VDirectiveManager -> VSlotOutletDirective -> VNode.)
|
|
@@ -9238,6 +9239,8 @@ class VSlotOutletDirective {
|
|
|
9238
9239
|
slot.replaceWith(fragment);
|
|
9239
9240
|
// Initial rendering
|
|
9240
9241
|
this.#contentVNode.forceUpdate();
|
|
9242
|
+
// Components in the slot content expand once it is in the document.
|
|
9243
|
+
this.#contentVNode.expandComponents();
|
|
9241
9244
|
}
|
|
9242
9245
|
/**
|
|
9243
9246
|
* Re-evaluates the slot props (component-side change) and pushes them into
|
|
@@ -9854,6 +9857,31 @@ class VNode {
|
|
|
9854
9857
|
* remove the entire fragment atomically.
|
|
9855
9858
|
*/
|
|
9856
9859
|
#fragmentRange;
|
|
9860
|
+
/**
|
|
9861
|
+
* Custom element tags already reported by
|
|
9862
|
+
* {@link VNode.#warnIfUnknownCustomElement}.
|
|
9863
|
+
*/
|
|
9864
|
+
static #warnedUnknownTags = new Set();
|
|
9865
|
+
/**
|
|
9866
|
+
* Warns about a hyphenated tag that no one has registered — a forgotten
|
|
9867
|
+
* import, a missing defineComponent() call, or a typo in the tag name.
|
|
9868
|
+
* Such an element is compiled as an ordinary element and renders its own
|
|
9869
|
+
* children, which looks enough like a working page to cost an afternoon.
|
|
9870
|
+
* Reported once per tag; third-party custom elements are recognised
|
|
9871
|
+
* through the registry the browser keeps.
|
|
9872
|
+
*/
|
|
9873
|
+
static #warnIfUnknownCustomElement(nodeName) {
|
|
9874
|
+
const tag = nodeName.toLowerCase();
|
|
9875
|
+
if (!tag.includes('-') || VNode.#warnedUnknownTags.has(tag)) {
|
|
9876
|
+
return;
|
|
9877
|
+
}
|
|
9878
|
+
if (typeof customElements !== 'undefined' && customElements.get(tag)) {
|
|
9879
|
+
return;
|
|
9880
|
+
}
|
|
9881
|
+
VNode.#warnedUnknownTags.add(tag);
|
|
9882
|
+
console.warn(`[ichigo] <${tag}>: unknown custom element — nothing has registered this tag.`
|
|
9883
|
+
+ ' Did you forget to import its module or call defineComponent(), or is the tag misspelled?');
|
|
9884
|
+
}
|
|
9857
9885
|
/**
|
|
9858
9886
|
* Creates an instance of the virtual node.
|
|
9859
9887
|
* @param args The initialization arguments for the virtual node.
|
|
@@ -9885,6 +9913,9 @@ class VNode {
|
|
|
9885
9913
|
if (isComponent) {
|
|
9886
9914
|
element._ichigoHost = { vNode: this };
|
|
9887
9915
|
}
|
|
9916
|
+
else {
|
|
9917
|
+
VNode.#warnIfUnknownCustomElement(this.#nodeName);
|
|
9918
|
+
}
|
|
9888
9919
|
// Initialize child virtual nodes
|
|
9889
9920
|
this.#childVNodes = [];
|
|
9890
9921
|
// Initialize directive manager
|
|
@@ -9943,6 +9974,37 @@ class VNode {
|
|
|
9943
9974
|
// Register this node as a dependent of the parent node, if any
|
|
9944
9975
|
this.#closers = this.#parentVNode?.addDependent(this);
|
|
9945
9976
|
}
|
|
9977
|
+
/**
|
|
9978
|
+
* Expands the component elements this application compiled in this subtree
|
|
9979
|
+
* but has not expanded yet, parents before their children.
|
|
9980
|
+
*
|
|
9981
|
+
* This is the ONLY thing that expands a component. It is deliberately a
|
|
9982
|
+
* separate step from compilation rather than a call at the end of the
|
|
9983
|
+
* constructor: a v-if / v-for clone is compiled while it is still detached
|
|
9984
|
+
* (so that its directives run before anything can observe a half-built
|
|
9985
|
+
* subtree), and expanding a detached element would mount a component
|
|
9986
|
+
* application outside the document. The callers therefore compile, insert,
|
|
9987
|
+
* and then call this — see VApplication.mount, VConditionalDirective,
|
|
9988
|
+
* VForDirective and VSlotOutletDirective.
|
|
9989
|
+
*
|
|
9990
|
+
* Walking only {@link childVNodes} keeps the traversal inside this
|
|
9991
|
+
* application: the internals of an expanded component were never compiled
|
|
9992
|
+
* here, so they are not reachable and are left to their own application.
|
|
9993
|
+
* A templatized node is skipped whole — it is a template source, and its
|
|
9994
|
+
* clones expand when they are inserted.
|
|
9995
|
+
*/
|
|
9996
|
+
expandComponents() {
|
|
9997
|
+
if (this.#templatized) {
|
|
9998
|
+
return;
|
|
9999
|
+
}
|
|
10000
|
+
if (this.#nodeType === Node.ELEMENT_NODE && IchigoElementRegistry.has(this.#nodeName)) {
|
|
10001
|
+
const element = this.#node;
|
|
10002
|
+
if (element._ichigoExpanded !== true) {
|
|
10003
|
+
element._ichigoExpand?.();
|
|
10004
|
+
}
|
|
10005
|
+
}
|
|
10006
|
+
this.#childVNodes?.forEach(child => child.expandComponents());
|
|
10007
|
+
}
|
|
9946
10008
|
/**
|
|
9947
10009
|
* The application instance associated with this virtual node.
|
|
9948
10010
|
*/
|
|
@@ -10743,11 +10805,10 @@ class VConditionalDirective {
|
|
|
10743
10805
|
}
|
|
10744
10806
|
// Clone the original node and create a new VNode for it
|
|
10745
10807
|
const clone = this.#cloneNode();
|
|
10746
|
-
//
|
|
10747
|
-
//
|
|
10748
|
-
//
|
|
10749
|
-
//
|
|
10750
|
-
// element's internal template content as its own VNode tree.
|
|
10808
|
+
// Compile the clone BEFORE inserting it, so its directives run against a
|
|
10809
|
+
// subtree nothing else can observe yet (v-if inside creates anchors and
|
|
10810
|
+
// detaches template sources). Components inside are expanded afterwards,
|
|
10811
|
+
// once the clone is in the document — see expandComponents() below.
|
|
10751
10812
|
// Pass the current bindings to ensure loop variables from v-for are available
|
|
10752
10813
|
const vNode = new VNode({
|
|
10753
10814
|
node: clone,
|
|
@@ -10762,12 +10823,16 @@ class VConditionalDirective {
|
|
|
10762
10823
|
vNode.fragmentRange = VFragmentRange.insert(anchorParent, nextSibling, 'vif-fragment', clone);
|
|
10763
10824
|
this.#renderedVNode = vNode;
|
|
10764
10825
|
this.#renderedVNode.forceUpdate();
|
|
10826
|
+
this.#renderedVNode.expandComponents();
|
|
10765
10827
|
return;
|
|
10766
10828
|
}
|
|
10767
10829
|
const nodeToInsert = vNode.anchorNode || clone;
|
|
10768
10830
|
anchorParent?.insertBefore(nodeToInsert, nextSibling);
|
|
10769
10831
|
this.#renderedVNode = vNode;
|
|
10770
10832
|
this.#renderedVNode.forceUpdate();
|
|
10833
|
+
// Components expand once the clone is in the document and its bindings
|
|
10834
|
+
// have been applied, so they mount connected and with their props set.
|
|
10835
|
+
this.#renderedVNode.expandComponents();
|
|
10771
10836
|
}
|
|
10772
10837
|
/**
|
|
10773
10838
|
* Removes the node from the DOM.
|
|
@@ -11224,6 +11289,7 @@ class VForDirective {
|
|
|
11224
11289
|
vNode.fragmentRange = range;
|
|
11225
11290
|
newRenderedItems.push({ key, vNode });
|
|
11226
11291
|
vNode.forceUpdate();
|
|
11292
|
+
vNode.expandComponents();
|
|
11227
11293
|
prevNode = range.lastNode;
|
|
11228
11294
|
continue;
|
|
11229
11295
|
}
|
|
@@ -11238,6 +11304,10 @@ class VForDirective {
|
|
|
11238
11304
|
}
|
|
11239
11305
|
newRenderedItems.push({ key, vNode });
|
|
11240
11306
|
vNode.forceUpdate();
|
|
11307
|
+
// Components expand once the clone is in the document and its
|
|
11308
|
+
// bindings have been applied, so they mount connected and with
|
|
11309
|
+
// their props set.
|
|
11310
|
+
vNode.expandComponents();
|
|
11241
11311
|
}
|
|
11242
11312
|
else {
|
|
11243
11313
|
// Reuse existing item
|
|
@@ -14807,6 +14877,10 @@ class VApplication {
|
|
|
14807
14877
|
});
|
|
14808
14878
|
// Initial rendering
|
|
14809
14879
|
this.#vNode.update();
|
|
14880
|
+
// Expand the components in the tree. Last, so every component element
|
|
14881
|
+
// has been compiled and has had its prop values delivered before its
|
|
14882
|
+
// template is cloned in. See VNode.expandComponents.
|
|
14883
|
+
this.#vNode.expandComponents();
|
|
14810
14884
|
// Remove v-cloak attributes after mounting
|
|
14811
14885
|
// v-cloak is used to hide un-compiled template until the app is ready
|
|
14812
14886
|
// Usage: Add CSS rule "[v-cloak] { display: none; }" to hide elements with v-cloak
|
|
@@ -15371,6 +15445,19 @@ class VDOM {
|
|
|
15371
15445
|
/**
|
|
15372
15446
|
* Base class for ichigo.js-backed Web Components (Light DOM, no Shadow DOM).
|
|
15373
15447
|
*
|
|
15448
|
+
* Expansion — cloning the template into this element — is driven by the
|
|
15449
|
+
* application that owns the element, not by connectedCallback: VNode compiles
|
|
15450
|
+
* the element first (installing the host context, delivering the prop values
|
|
15451
|
+
* and compiling the authored slot content in the owner's scope) and only then
|
|
15452
|
+
* calls {@link _ichigoExpand}. That leaves connectedCallback a single job,
|
|
15453
|
+
* re-attachment; see there.
|
|
15454
|
+
*
|
|
15455
|
+
* The component's <template> must be present in the document, and
|
|
15456
|
+
* defineComponent() must have run, before the owning application is mounted.
|
|
15457
|
+
* That is the application's responsibility. A missing template is reported as
|
|
15458
|
+
* a warning and the element is left empty — it is never silently retried,
|
|
15459
|
+
* because an app that renders anyway is an app whose bug cannot be found.
|
|
15460
|
+
*
|
|
15374
15461
|
* Mount timing:
|
|
15375
15462
|
* - If the component declares no props, the VApplication is mounted synchronously
|
|
15376
15463
|
* at the end of connectedCallback (the template is known, no props to wait for).
|
|
@@ -15422,13 +15509,6 @@ class IchigoElement extends HTMLElement {
|
|
|
15422
15509
|
* belong to this component's VApplication and scope).
|
|
15423
15510
|
*/
|
|
15424
15511
|
_ichigoExpanded = false;
|
|
15425
|
-
/**
|
|
15426
|
-
* Host context installed by the parent application's VNode when it
|
|
15427
|
-
* compiles this element. Gives component-boundary features (e.g. scoped
|
|
15428
|
-
* slot outlets) access to the parent scope. Undefined when the element is
|
|
15429
|
-
* placed outside any ichigo application.
|
|
15430
|
-
*/
|
|
15431
|
-
_ichigoHost;
|
|
15432
15512
|
/**
|
|
15433
15513
|
* The scoped slot templates captured from this element's children, keyed
|
|
15434
15514
|
* by slot name ('default' for `v-slot` without a name). Read by
|
|
@@ -15437,20 +15517,42 @@ class IchigoElement extends HTMLElement {
|
|
|
15437
15517
|
get _ichigoScopedSlots() {
|
|
15438
15518
|
return this.#slotCache?.scopedSlots;
|
|
15439
15519
|
}
|
|
15520
|
+
/**
|
|
15521
|
+
* Handles RE-attachment, and nothing else.
|
|
15522
|
+
*
|
|
15523
|
+
* A first connection is not what expands this element: the owning
|
|
15524
|
+
* application does that from {@link _ichigoExpand} once it has compiled the
|
|
15525
|
+
* element. So a connection event on a not-yet-expanded element means the
|
|
15526
|
+
* owner has not reached it yet, and the right thing to do is nothing. That
|
|
15527
|
+
* covers every case the old guards enumerated one by one — a v-if / v-for
|
|
15528
|
+
* template source, an element inside an enclosing component's template
|
|
15529
|
+
* clone, a clone inserted before its directive expands it.
|
|
15530
|
+
*
|
|
15531
|
+
* An expanded element whose mount root has been torn down, on the other
|
|
15532
|
+
* hand, was disconnected and is now coming back: v-for reorders relocate
|
|
15533
|
+
* the host element, which disconnects and reconnects it. Its children are
|
|
15534
|
+
* the previous expansion, not authored slot content, so it re-expands from
|
|
15535
|
+
* the cached slot nodes. Testing the mount root rather than the expansion
|
|
15536
|
+
* flag alone keeps this from firing on an element that was expanded while
|
|
15537
|
+
* detached and is being inserted for the first time.
|
|
15538
|
+
*/
|
|
15440
15539
|
connectedCallback() {
|
|
15441
|
-
|
|
15442
|
-
|
|
15443
|
-
// family / v-for) is a template source: the owning application clones it
|
|
15444
|
-
// and inserts the clones (whose directive attributes are stripped during
|
|
15445
|
-
// clone compilation, so the clones expand normally). Expanding the source
|
|
15446
|
-
// here would bake the expansion into every clone, and the clone's
|
|
15447
|
-
// internals would then be compiled in the parent scope.
|
|
15448
|
-
if (this.hasAttribute(StandardDirectiveName.V_IF) ||
|
|
15449
|
-
this.hasAttribute(StandardDirectiveName.V_ELSE_IF) ||
|
|
15450
|
-
this.hasAttribute(StandardDirectiveName.V_ELSE) ||
|
|
15451
|
-
this.hasAttribute(StandardDirectiveName.V_FOR)) {
|
|
15452
|
-
return;
|
|
15540
|
+
if (this._ichigoExpanded && !this.#mountRoot) {
|
|
15541
|
+
this._ichigoExpand();
|
|
15453
15542
|
}
|
|
15543
|
+
}
|
|
15544
|
+
/**
|
|
15545
|
+
* Expands this element's template. Called by the application that owns the
|
|
15546
|
+
* element, right after it compiled it (VNode.expandComponents): the host
|
|
15547
|
+
* context is installed, the prop bindings have delivered their values and
|
|
15548
|
+
* the authored slot content has been compiled in the owner's scope, so the
|
|
15549
|
+
* capture below sees owner-compiled nodes and the component's own
|
|
15550
|
+
* application starts with its props already in hand.
|
|
15551
|
+
*
|
|
15552
|
+
* Also called by {@link connectedCallback} to rebuild the expansion after a
|
|
15553
|
+
* move.
|
|
15554
|
+
*/
|
|
15555
|
+
_ichigoExpand() {
|
|
15454
15556
|
// --- 0b. Reclaim prop values assigned before upgrade ---
|
|
15455
15557
|
// A plain property set on the instance (e.g. by a binding delivered
|
|
15456
15558
|
// while the element was detached or not yet upgraded) is an own data
|
|
@@ -15466,13 +15568,15 @@ class IchigoElement extends HTMLElement {
|
|
|
15466
15568
|
this[prop] = value;
|
|
15467
15569
|
}
|
|
15468
15570
|
}
|
|
15469
|
-
// --- 0c.
|
|
15470
|
-
//
|
|
15471
|
-
//
|
|
15472
|
-
//
|
|
15473
|
-
//
|
|
15571
|
+
// --- 0c. Resolve the template ---
|
|
15572
|
+
// Having the <template> in the document by now is the application's
|
|
15573
|
+
// contract (see the class doc). Report the breach and leave the element
|
|
15574
|
+
// empty: rendering something plausible here would hide the bug at the
|
|
15575
|
+
// one moment it is still cheap to find.
|
|
15474
15576
|
const templateEl = document.querySelector(ctor._template);
|
|
15475
15577
|
if (!templateEl || !(templateEl instanceof HTMLTemplateElement)) {
|
|
15578
|
+
IchigoElement.#warnOncePerTag(this.tagName, `template '${ctor._template}' was not found in the document. `
|
|
15579
|
+
+ 'Inject the <template> and call defineComponent() before mounting the application.');
|
|
15476
15580
|
return;
|
|
15477
15581
|
}
|
|
15478
15582
|
// --- 1. Capture slot content (first connection only) ---
|
|
@@ -15787,6 +15891,23 @@ class IchigoElement extends HTMLElement {
|
|
|
15787
15891
|
#warn(message) {
|
|
15788
15892
|
console.warn(`[ichigo] <${this.tagName.toLowerCase()}>: ${message}`);
|
|
15789
15893
|
}
|
|
15894
|
+
/**
|
|
15895
|
+
* Tags already reported by {@link #warnOncePerTag}.
|
|
15896
|
+
*/
|
|
15897
|
+
static #warnedTags = new Set();
|
|
15898
|
+
/**
|
|
15899
|
+
* Reports a per-component-type problem once. A missing template breaks
|
|
15900
|
+
* every instance, and a v-for over a hundred rows would otherwise print a
|
|
15901
|
+
* hundred identical lines and bury the first one.
|
|
15902
|
+
*/
|
|
15903
|
+
static #warnOncePerTag(tagName, message) {
|
|
15904
|
+
const tag = tagName.toLowerCase();
|
|
15905
|
+
if (IchigoElement.#warnedTags.has(tag)) {
|
|
15906
|
+
return;
|
|
15907
|
+
}
|
|
15908
|
+
IchigoElement.#warnedTags.add(tag);
|
|
15909
|
+
console.warn(`[ichigo] <${tag}>: ${message}`);
|
|
15910
|
+
}
|
|
15790
15911
|
}
|
|
15791
15912
|
|
|
15792
15913
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|