@mintjamsinc/ichigojs 0.1.63 → 0.1.65
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/ichigo.cjs +180 -23
- package/dist/ichigo.cjs.map +1 -1
- package/dist/ichigo.esm.js +180 -23
- 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 +180 -23
- package/dist/ichigo.umd.js.map +1 -1
- package/dist/ichigo.umd.min.js +1 -1
- package/dist/types/ichigo/directives/VBindDirective.d.ts +5 -0
- package/dist/types/ichigo/directives/VDirectiveManager.d.ts +9 -0
- package/package.json +1 -1
package/dist/ichigo.cjs
CHANGED
|
@@ -7443,6 +7443,13 @@
|
|
|
7443
7443
|
get expression() {
|
|
7444
7444
|
return this.#expression;
|
|
7445
7445
|
}
|
|
7446
|
+
/**
|
|
7447
|
+
* Evaluates the bound expression and returns the current value.
|
|
7448
|
+
* Returns undefined when no evaluator is available (e.g., empty expression).
|
|
7449
|
+
*/
|
|
7450
|
+
evaluate() {
|
|
7451
|
+
return this.#evaluator?.evaluate();
|
|
7452
|
+
}
|
|
7446
7453
|
/**
|
|
7447
7454
|
* @inheritdoc
|
|
7448
7455
|
*/
|
|
@@ -7603,18 +7610,25 @@
|
|
|
7603
7610
|
* Returns true when the target is a custom element and the binding should be
|
|
7604
7611
|
* delivered as a property rather than an HTML attribute.
|
|
7605
7612
|
*
|
|
7606
|
-
*
|
|
7613
|
+
* Three conditions trigger property delivery:
|
|
7607
7614
|
* 1. The value is an object or array — serialising these to a string attribute
|
|
7608
7615
|
* would lose type information.
|
|
7609
7616
|
* 2. The element exposes a matching property accessor (e.g. a prop declared via
|
|
7610
7617
|
* defineComponent), even when the value is a primitive.
|
|
7618
|
+
* 3. The element declares a matching prop in its static _props (case-insensitive
|
|
7619
|
+
* and kebab-case → camelCase tolerant), so primitive values reach the
|
|
7620
|
+
* reactive binding via the generated setter instead of being lost as a
|
|
7621
|
+
* plain HTML attribute that no attributeChangedCallback observes.
|
|
7611
7622
|
*/
|
|
7612
7623
|
#isCustomElementProperty(element, name, value) {
|
|
7613
7624
|
if (!element.tagName.includes('-')) {
|
|
7614
7625
|
return false;
|
|
7615
7626
|
}
|
|
7616
7627
|
const isObjectOrArray = Array.isArray(value) || (typeof value === 'object' && value !== null);
|
|
7617
|
-
|
|
7628
|
+
if (isObjectOrArray || name in element) {
|
|
7629
|
+
return true;
|
|
7630
|
+
}
|
|
7631
|
+
return this.#findDeclaredProp(element, name) !== undefined;
|
|
7618
7632
|
}
|
|
7619
7633
|
/**
|
|
7620
7634
|
* Resolves the actual property name on a custom element for a given
|
|
@@ -7630,20 +7644,25 @@
|
|
|
7630
7644
|
if (name in element) {
|
|
7631
7645
|
return name;
|
|
7632
7646
|
}
|
|
7633
|
-
|
|
7647
|
+
return this.#findDeclaredProp(element, name) ?? name;
|
|
7648
|
+
}
|
|
7649
|
+
/**
|
|
7650
|
+
* Looks up a declared prop on a custom element constructor whose name matches
|
|
7651
|
+
* the given attribute name, treating the comparison as case-insensitive and
|
|
7652
|
+
* tolerant of kebab-case → camelCase conversion. Returns the canonical prop
|
|
7653
|
+
* name (as declared) when a match is found, or undefined otherwise.
|
|
7654
|
+
*/
|
|
7655
|
+
#findDeclaredProp(element, name) {
|
|
7634
7656
|
const props = element.constructor._props;
|
|
7635
|
-
if (Array.isArray(props)) {
|
|
7636
|
-
|
|
7637
|
-
const camelName = this.#kebabToCamel(lowerName);
|
|
7638
|
-
const match = props.find(p => {
|
|
7639
|
-
const lowerProp = p.toLowerCase();
|
|
7640
|
-
return lowerProp === lowerName || lowerProp === camelName.toLowerCase() || p === camelName;
|
|
7641
|
-
});
|
|
7642
|
-
if (match) {
|
|
7643
|
-
return match;
|
|
7644
|
-
}
|
|
7657
|
+
if (!Array.isArray(props)) {
|
|
7658
|
+
return undefined;
|
|
7645
7659
|
}
|
|
7646
|
-
|
|
7660
|
+
const lowerName = name.toLowerCase();
|
|
7661
|
+
const camelLower = this.#kebabToCamel(lowerName).toLowerCase();
|
|
7662
|
+
return props.find(p => {
|
|
7663
|
+
const lowerProp = p.toLowerCase();
|
|
7664
|
+
return lowerProp === lowerName || lowerProp === camelLower;
|
|
7665
|
+
});
|
|
7647
7666
|
}
|
|
7648
7667
|
/**
|
|
7649
7668
|
* Converts kebab-case to camelCase (e.g. `user-name` → `userName`).
|
|
@@ -8643,6 +8662,29 @@
|
|
|
8643
8662
|
get keyDirective() {
|
|
8644
8663
|
return this.#keyDirective;
|
|
8645
8664
|
}
|
|
8665
|
+
/**
|
|
8666
|
+
* Finds a VBindDirective that binds the given attribute name (e.g. "value",
|
|
8667
|
+
* "true-value", "false-value"). Returns undefined if no matching v-bind
|
|
8668
|
+
* directive is registered on this node.
|
|
8669
|
+
*
|
|
8670
|
+
* Used by directives such as v-model that need to read the typed value of a
|
|
8671
|
+
* sibling v-bind without depending on the attribute order in the source HTML.
|
|
8672
|
+
*/
|
|
8673
|
+
findBindDirective(attrName) {
|
|
8674
|
+
if (!this.#directives || this.#directives.length === 0) {
|
|
8675
|
+
return undefined;
|
|
8676
|
+
}
|
|
8677
|
+
for (const directive of this.#directives) {
|
|
8678
|
+
if (directive.name !== StandardDirectiveName.V_BIND) {
|
|
8679
|
+
continue;
|
|
8680
|
+
}
|
|
8681
|
+
const bindDirective = directive;
|
|
8682
|
+
if (bindDirective.attributeName === attrName) {
|
|
8683
|
+
return bindDirective;
|
|
8684
|
+
}
|
|
8685
|
+
}
|
|
8686
|
+
return undefined;
|
|
8687
|
+
}
|
|
8646
8688
|
/**
|
|
8647
8689
|
* Gets the VBindDirective for options specific to the given directive name.
|
|
8648
8690
|
* Searches in order: `:options.{directive}` -> `:options`
|
|
@@ -11096,14 +11138,13 @@
|
|
|
11096
11138
|
* @inheritdoc
|
|
11097
11139
|
*/
|
|
11098
11140
|
get domUpdater() {
|
|
11099
|
-
const
|
|
11100
|
-
// Create and return the DOM updater
|
|
11141
|
+
const self = this;
|
|
11101
11142
|
const updater = {
|
|
11102
11143
|
get dependentIdentifiers() {
|
|
11103
|
-
return
|
|
11144
|
+
return self.#collectDependentIdentifiers();
|
|
11104
11145
|
},
|
|
11105
11146
|
applyToDOM: () => {
|
|
11106
|
-
|
|
11147
|
+
self.#render();
|
|
11107
11148
|
}
|
|
11108
11149
|
};
|
|
11109
11150
|
return updater;
|
|
@@ -11118,7 +11159,27 @@
|
|
|
11118
11159
|
* @inheritdoc
|
|
11119
11160
|
*/
|
|
11120
11161
|
get dependentIdentifiers() {
|
|
11121
|
-
return this.#
|
|
11162
|
+
return this.#collectDependentIdentifiers();
|
|
11163
|
+
}
|
|
11164
|
+
/**
|
|
11165
|
+
* Collects identifiers this directive's render depends on. For checkboxes
|
|
11166
|
+
* this includes the v-model expression itself plus the expressions bound to
|
|
11167
|
+
* `:value`, `:true-value`, and `:false-value`, since the rendered checked
|
|
11168
|
+
* state changes when any of these change.
|
|
11169
|
+
*/
|
|
11170
|
+
#collectDependentIdentifiers() {
|
|
11171
|
+
const ids = new Set(this.#evaluator?.dependentIdentifiers ?? []);
|
|
11172
|
+
const element = this.#vNode.node;
|
|
11173
|
+
if (element instanceof HTMLInputElement && element.type === 'checkbox') {
|
|
11174
|
+
const manager = this.#vNode.directiveManager;
|
|
11175
|
+
for (const attrName of ['value', 'true-value', 'false-value']) {
|
|
11176
|
+
const bindDirective = manager?.findBindDirective(attrName);
|
|
11177
|
+
if (bindDirective) {
|
|
11178
|
+
bindDirective.dependentIdentifiers.forEach(id => ids.add(id));
|
|
11179
|
+
}
|
|
11180
|
+
}
|
|
11181
|
+
}
|
|
11182
|
+
return Array.from(ids);
|
|
11122
11183
|
}
|
|
11123
11184
|
/**
|
|
11124
11185
|
* @inheritdoc
|
|
@@ -11198,7 +11259,7 @@
|
|
|
11198
11259
|
// Update the element based on its type
|
|
11199
11260
|
if (element instanceof HTMLInputElement) {
|
|
11200
11261
|
if (element.type === 'checkbox') {
|
|
11201
|
-
element
|
|
11262
|
+
this.#renderCheckbox(element, value);
|
|
11202
11263
|
}
|
|
11203
11264
|
else if (element.type === 'radio') {
|
|
11204
11265
|
// Prefer the original typed value stored by VBindDirective (:value binding)
|
|
@@ -11231,7 +11292,7 @@
|
|
|
11231
11292
|
// Get the new value based on element type
|
|
11232
11293
|
if (target instanceof HTMLInputElement) {
|
|
11233
11294
|
if (target.type === 'checkbox') {
|
|
11234
|
-
newValue = target
|
|
11295
|
+
newValue = this.#computeCheckboxNewValue(target);
|
|
11235
11296
|
}
|
|
11236
11297
|
else if (target.type === 'radio') {
|
|
11237
11298
|
// Prefer the original typed value stored by VBindDirective (:value binding)
|
|
@@ -11247,13 +11308,109 @@
|
|
|
11247
11308
|
else if (target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement) {
|
|
11248
11309
|
newValue = target.value;
|
|
11249
11310
|
}
|
|
11250
|
-
// Apply modifiers to the value
|
|
11251
|
-
|
|
11311
|
+
// Apply modifiers to the value (skip for checkboxes: their value
|
|
11312
|
+
// is either boolean, a custom true/false value, or an array, none
|
|
11313
|
+
// of which should be coerced by .trim or .number).
|
|
11314
|
+
const isCheckbox = target instanceof HTMLInputElement && target.type === 'checkbox';
|
|
11315
|
+
if (!isCheckbox) {
|
|
11316
|
+
newValue = this.#applyModifiers(newValue);
|
|
11317
|
+
}
|
|
11252
11318
|
// Update the binding
|
|
11253
11319
|
this.#updateBinding(newValue);
|
|
11254
11320
|
};
|
|
11255
11321
|
element.addEventListener(eventName, this.#listener);
|
|
11256
11322
|
}
|
|
11323
|
+
/**
|
|
11324
|
+
* Renders a checkbox in one of three modes (Vue-compatible):
|
|
11325
|
+
* 1. Array binding: the bound value is an array; the checkbox is checked
|
|
11326
|
+
* when its element-value is a member of that array.
|
|
11327
|
+
* 2. true-value/false-value binding: when `:true-value` (and optionally
|
|
11328
|
+
* `:false-value`) is provided via v-bind, the checkbox is checked
|
|
11329
|
+
* when the bound value strictly equals the resolved true-value.
|
|
11330
|
+
* 3. Boolean binding (default): the bound value is coerced to boolean.
|
|
11331
|
+
*/
|
|
11332
|
+
#renderCheckbox(element, value) {
|
|
11333
|
+
if (Array.isArray(value)) {
|
|
11334
|
+
const elementValue = this.#resolveCheckboxElementValue(element);
|
|
11335
|
+
element.checked = value.indexOf(elementValue) !== -1;
|
|
11336
|
+
return;
|
|
11337
|
+
}
|
|
11338
|
+
const trueValueDescriptor = this.#resolveCheckboxTrueFalseValues(element);
|
|
11339
|
+
if (trueValueDescriptor) {
|
|
11340
|
+
element.checked = value === trueValueDescriptor.trueValue;
|
|
11341
|
+
return;
|
|
11342
|
+
}
|
|
11343
|
+
element.checked = !!value;
|
|
11344
|
+
}
|
|
11345
|
+
/**
|
|
11346
|
+
* Computes the value to write back to the bound expression when a checkbox
|
|
11347
|
+
* change event fires. Mirrors the three-mode logic of #renderCheckbox.
|
|
11348
|
+
*
|
|
11349
|
+
* For array binding, the current value of the bound expression is read so
|
|
11350
|
+
* that a fresh array can be returned (the existing array is not mutated,
|
|
11351
|
+
* which preserves reactivity semantics).
|
|
11352
|
+
*/
|
|
11353
|
+
#computeCheckboxNewValue(target) {
|
|
11354
|
+
const currentValue = this.#evaluator?.evaluate();
|
|
11355
|
+
if (Array.isArray(currentValue)) {
|
|
11356
|
+
const elementValue = this.#resolveCheckboxElementValue(target);
|
|
11357
|
+
const next = currentValue.slice();
|
|
11358
|
+
const index = next.indexOf(elementValue);
|
|
11359
|
+
if (target.checked) {
|
|
11360
|
+
if (index === -1) {
|
|
11361
|
+
next.push(elementValue);
|
|
11362
|
+
}
|
|
11363
|
+
}
|
|
11364
|
+
else {
|
|
11365
|
+
if (index !== -1) {
|
|
11366
|
+
next.splice(index, 1);
|
|
11367
|
+
}
|
|
11368
|
+
}
|
|
11369
|
+
return next;
|
|
11370
|
+
}
|
|
11371
|
+
const trueValueDescriptor = this.#resolveCheckboxTrueFalseValues(target);
|
|
11372
|
+
if (trueValueDescriptor) {
|
|
11373
|
+
return target.checked ? trueValueDescriptor.trueValue : trueValueDescriptor.falseValue;
|
|
11374
|
+
}
|
|
11375
|
+
return target.checked;
|
|
11376
|
+
}
|
|
11377
|
+
/**
|
|
11378
|
+
* Resolves the typed element value for a checkbox. Prefers the value bound
|
|
11379
|
+
* via `:value` (evaluated through the sibling VBindDirective so type is
|
|
11380
|
+
* preserved), then the typed value previously stored on the element by
|
|
11381
|
+
* VBindDirective, and finally the raw string `value` attribute.
|
|
11382
|
+
*/
|
|
11383
|
+
#resolveCheckboxElementValue(element) {
|
|
11384
|
+
const bindDirective = this.#vNode.directiveManager?.findBindDirective('value');
|
|
11385
|
+
if (bindDirective) {
|
|
11386
|
+
return bindDirective.evaluate();
|
|
11387
|
+
}
|
|
11388
|
+
if (element._value !== undefined) {
|
|
11389
|
+
return element._value;
|
|
11390
|
+
}
|
|
11391
|
+
return element.value;
|
|
11392
|
+
}
|
|
11393
|
+
/**
|
|
11394
|
+
* Resolves the (true-value, false-value) pair for a checkbox if either is
|
|
11395
|
+
* bound via `:true-value` or `:false-value`. Returns undefined when no
|
|
11396
|
+
* true/false value binding is present, signalling that the default boolean
|
|
11397
|
+
* mode should be used.
|
|
11398
|
+
*
|
|
11399
|
+
* If only one of the two is bound, the other defaults match Vue: an unbound
|
|
11400
|
+
* true-value defaults to literal `true`, an unbound false-value to `false`.
|
|
11401
|
+
*/
|
|
11402
|
+
#resolveCheckboxTrueFalseValues(element) {
|
|
11403
|
+
const manager = this.#vNode.directiveManager;
|
|
11404
|
+
const trueBind = manager?.findBindDirective('true-value');
|
|
11405
|
+
const falseBind = manager?.findBindDirective('false-value');
|
|
11406
|
+
if (!trueBind && !falseBind) {
|
|
11407
|
+
return undefined;
|
|
11408
|
+
}
|
|
11409
|
+
return {
|
|
11410
|
+
trueValue: trueBind ? trueBind.evaluate() : true,
|
|
11411
|
+
falseValue: falseBind ? falseBind.evaluate() : false,
|
|
11412
|
+
};
|
|
11413
|
+
}
|
|
11257
11414
|
/**
|
|
11258
11415
|
* Applies modifiers to the input value.
|
|
11259
11416
|
* @param value The value to process.
|