@mintjamsinc/ichigojs 0.1.64 → 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 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
  */
@@ -8655,6 +8662,29 @@
8655
8662
  get keyDirective() {
8656
8663
  return this.#keyDirective;
8657
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
+ }
8658
8688
  /**
8659
8689
  * Gets the VBindDirective for options specific to the given directive name.
8660
8690
  * Searches in order: `:options.{directive}` -> `:options`
@@ -11108,14 +11138,13 @@
11108
11138
  * @inheritdoc
11109
11139
  */
11110
11140
  get domUpdater() {
11111
- const identifiers = this.#evaluator?.dependentIdentifiers ?? [];
11112
- // Create and return the DOM updater
11141
+ const self = this;
11113
11142
  const updater = {
11114
11143
  get dependentIdentifiers() {
11115
- return identifiers;
11144
+ return self.#collectDependentIdentifiers();
11116
11145
  },
11117
11146
  applyToDOM: () => {
11118
- this.#render();
11147
+ self.#render();
11119
11148
  }
11120
11149
  };
11121
11150
  return updater;
@@ -11130,7 +11159,27 @@
11130
11159
  * @inheritdoc
11131
11160
  */
11132
11161
  get dependentIdentifiers() {
11133
- return this.#evaluator?.dependentIdentifiers ?? [];
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);
11134
11183
  }
11135
11184
  /**
11136
11185
  * @inheritdoc
@@ -11210,7 +11259,7 @@
11210
11259
  // Update the element based on its type
11211
11260
  if (element instanceof HTMLInputElement) {
11212
11261
  if (element.type === 'checkbox') {
11213
- element.checked = !!value;
11262
+ this.#renderCheckbox(element, value);
11214
11263
  }
11215
11264
  else if (element.type === 'radio') {
11216
11265
  // Prefer the original typed value stored by VBindDirective (:value binding)
@@ -11243,7 +11292,7 @@
11243
11292
  // Get the new value based on element type
11244
11293
  if (target instanceof HTMLInputElement) {
11245
11294
  if (target.type === 'checkbox') {
11246
- newValue = target.checked;
11295
+ newValue = this.#computeCheckboxNewValue(target);
11247
11296
  }
11248
11297
  else if (target.type === 'radio') {
11249
11298
  // Prefer the original typed value stored by VBindDirective (:value binding)
@@ -11259,13 +11308,109 @@
11259
11308
  else if (target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement) {
11260
11309
  newValue = target.value;
11261
11310
  }
11262
- // Apply modifiers to the value
11263
- newValue = this.#applyModifiers(newValue);
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
+ }
11264
11318
  // Update the binding
11265
11319
  this.#updateBinding(newValue);
11266
11320
  };
11267
11321
  element.addEventListener(eventName, this.#listener);
11268
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
+ }
11269
11414
  /**
11270
11415
  * Applies modifiers to the input value.
11271
11416
  * @param value The value to process.