@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.
@@ -7437,6 +7437,13 @@ class VBindDirective {
7437
7437
  get expression() {
7438
7438
  return this.#expression;
7439
7439
  }
7440
+ /**
7441
+ * Evaluates the bound expression and returns the current value.
7442
+ * Returns undefined when no evaluator is available (e.g., empty expression).
7443
+ */
7444
+ evaluate() {
7445
+ return this.#evaluator?.evaluate();
7446
+ }
7440
7447
  /**
7441
7448
  * @inheritdoc
7442
7449
  */
@@ -8649,6 +8656,29 @@ class VDirectiveManager {
8649
8656
  get keyDirective() {
8650
8657
  return this.#keyDirective;
8651
8658
  }
8659
+ /**
8660
+ * Finds a VBindDirective that binds the given attribute name (e.g. "value",
8661
+ * "true-value", "false-value"). Returns undefined if no matching v-bind
8662
+ * directive is registered on this node.
8663
+ *
8664
+ * Used by directives such as v-model that need to read the typed value of a
8665
+ * sibling v-bind without depending on the attribute order in the source HTML.
8666
+ */
8667
+ findBindDirective(attrName) {
8668
+ if (!this.#directives || this.#directives.length === 0) {
8669
+ return undefined;
8670
+ }
8671
+ for (const directive of this.#directives) {
8672
+ if (directive.name !== StandardDirectiveName.V_BIND) {
8673
+ continue;
8674
+ }
8675
+ const bindDirective = directive;
8676
+ if (bindDirective.attributeName === attrName) {
8677
+ return bindDirective;
8678
+ }
8679
+ }
8680
+ return undefined;
8681
+ }
8652
8682
  /**
8653
8683
  * Gets the VBindDirective for options specific to the given directive name.
8654
8684
  * Searches in order: `:options.{directive}` -> `:options`
@@ -11102,14 +11132,13 @@ class VModelDirective {
11102
11132
  * @inheritdoc
11103
11133
  */
11104
11134
  get domUpdater() {
11105
- const identifiers = this.#evaluator?.dependentIdentifiers ?? [];
11106
- // Create and return the DOM updater
11135
+ const self = this;
11107
11136
  const updater = {
11108
11137
  get dependentIdentifiers() {
11109
- return identifiers;
11138
+ return self.#collectDependentIdentifiers();
11110
11139
  },
11111
11140
  applyToDOM: () => {
11112
- this.#render();
11141
+ self.#render();
11113
11142
  }
11114
11143
  };
11115
11144
  return updater;
@@ -11124,7 +11153,27 @@ class VModelDirective {
11124
11153
  * @inheritdoc
11125
11154
  */
11126
11155
  get dependentIdentifiers() {
11127
- return this.#evaluator?.dependentIdentifiers ?? [];
11156
+ return this.#collectDependentIdentifiers();
11157
+ }
11158
+ /**
11159
+ * Collects identifiers this directive's render depends on. For checkboxes
11160
+ * this includes the v-model expression itself plus the expressions bound to
11161
+ * `:value`, `:true-value`, and `:false-value`, since the rendered checked
11162
+ * state changes when any of these change.
11163
+ */
11164
+ #collectDependentIdentifiers() {
11165
+ const ids = new Set(this.#evaluator?.dependentIdentifiers ?? []);
11166
+ const element = this.#vNode.node;
11167
+ if (element instanceof HTMLInputElement && element.type === 'checkbox') {
11168
+ const manager = this.#vNode.directiveManager;
11169
+ for (const attrName of ['value', 'true-value', 'false-value']) {
11170
+ const bindDirective = manager?.findBindDirective(attrName);
11171
+ if (bindDirective) {
11172
+ bindDirective.dependentIdentifiers.forEach(id => ids.add(id));
11173
+ }
11174
+ }
11175
+ }
11176
+ return Array.from(ids);
11128
11177
  }
11129
11178
  /**
11130
11179
  * @inheritdoc
@@ -11204,7 +11253,7 @@ class VModelDirective {
11204
11253
  // Update the element based on its type
11205
11254
  if (element instanceof HTMLInputElement) {
11206
11255
  if (element.type === 'checkbox') {
11207
- element.checked = !!value;
11256
+ this.#renderCheckbox(element, value);
11208
11257
  }
11209
11258
  else if (element.type === 'radio') {
11210
11259
  // Prefer the original typed value stored by VBindDirective (:value binding)
@@ -11237,7 +11286,7 @@ class VModelDirective {
11237
11286
  // Get the new value based on element type
11238
11287
  if (target instanceof HTMLInputElement) {
11239
11288
  if (target.type === 'checkbox') {
11240
- newValue = target.checked;
11289
+ newValue = this.#computeCheckboxNewValue(target);
11241
11290
  }
11242
11291
  else if (target.type === 'radio') {
11243
11292
  // Prefer the original typed value stored by VBindDirective (:value binding)
@@ -11253,13 +11302,109 @@ class VModelDirective {
11253
11302
  else if (target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement) {
11254
11303
  newValue = target.value;
11255
11304
  }
11256
- // Apply modifiers to the value
11257
- newValue = this.#applyModifiers(newValue);
11305
+ // Apply modifiers to the value (skip for checkboxes: their value
11306
+ // is either boolean, a custom true/false value, or an array, none
11307
+ // of which should be coerced by .trim or .number).
11308
+ const isCheckbox = target instanceof HTMLInputElement && target.type === 'checkbox';
11309
+ if (!isCheckbox) {
11310
+ newValue = this.#applyModifiers(newValue);
11311
+ }
11258
11312
  // Update the binding
11259
11313
  this.#updateBinding(newValue);
11260
11314
  };
11261
11315
  element.addEventListener(eventName, this.#listener);
11262
11316
  }
11317
+ /**
11318
+ * Renders a checkbox in one of three modes (Vue-compatible):
11319
+ * 1. Array binding: the bound value is an array; the checkbox is checked
11320
+ * when its element-value is a member of that array.
11321
+ * 2. true-value/false-value binding: when `:true-value` (and optionally
11322
+ * `:false-value`) is provided via v-bind, the checkbox is checked
11323
+ * when the bound value strictly equals the resolved true-value.
11324
+ * 3. Boolean binding (default): the bound value is coerced to boolean.
11325
+ */
11326
+ #renderCheckbox(element, value) {
11327
+ if (Array.isArray(value)) {
11328
+ const elementValue = this.#resolveCheckboxElementValue(element);
11329
+ element.checked = value.indexOf(elementValue) !== -1;
11330
+ return;
11331
+ }
11332
+ const trueValueDescriptor = this.#resolveCheckboxTrueFalseValues(element);
11333
+ if (trueValueDescriptor) {
11334
+ element.checked = value === trueValueDescriptor.trueValue;
11335
+ return;
11336
+ }
11337
+ element.checked = !!value;
11338
+ }
11339
+ /**
11340
+ * Computes the value to write back to the bound expression when a checkbox
11341
+ * change event fires. Mirrors the three-mode logic of #renderCheckbox.
11342
+ *
11343
+ * For array binding, the current value of the bound expression is read so
11344
+ * that a fresh array can be returned (the existing array is not mutated,
11345
+ * which preserves reactivity semantics).
11346
+ */
11347
+ #computeCheckboxNewValue(target) {
11348
+ const currentValue = this.#evaluator?.evaluate();
11349
+ if (Array.isArray(currentValue)) {
11350
+ const elementValue = this.#resolveCheckboxElementValue(target);
11351
+ const next = currentValue.slice();
11352
+ const index = next.indexOf(elementValue);
11353
+ if (target.checked) {
11354
+ if (index === -1) {
11355
+ next.push(elementValue);
11356
+ }
11357
+ }
11358
+ else {
11359
+ if (index !== -1) {
11360
+ next.splice(index, 1);
11361
+ }
11362
+ }
11363
+ return next;
11364
+ }
11365
+ const trueValueDescriptor = this.#resolveCheckboxTrueFalseValues(target);
11366
+ if (trueValueDescriptor) {
11367
+ return target.checked ? trueValueDescriptor.trueValue : trueValueDescriptor.falseValue;
11368
+ }
11369
+ return target.checked;
11370
+ }
11371
+ /**
11372
+ * Resolves the typed element value for a checkbox. Prefers the value bound
11373
+ * via `:value` (evaluated through the sibling VBindDirective so type is
11374
+ * preserved), then the typed value previously stored on the element by
11375
+ * VBindDirective, and finally the raw string `value` attribute.
11376
+ */
11377
+ #resolveCheckboxElementValue(element) {
11378
+ const bindDirective = this.#vNode.directiveManager?.findBindDirective('value');
11379
+ if (bindDirective) {
11380
+ return bindDirective.evaluate();
11381
+ }
11382
+ if (element._value !== undefined) {
11383
+ return element._value;
11384
+ }
11385
+ return element.value;
11386
+ }
11387
+ /**
11388
+ * Resolves the (true-value, false-value) pair for a checkbox if either is
11389
+ * bound via `:true-value` or `:false-value`. Returns undefined when no
11390
+ * true/false value binding is present, signalling that the default boolean
11391
+ * mode should be used.
11392
+ *
11393
+ * If only one of the two is bound, the other defaults match Vue: an unbound
11394
+ * true-value defaults to literal `true`, an unbound false-value to `false`.
11395
+ */
11396
+ #resolveCheckboxTrueFalseValues(element) {
11397
+ const manager = this.#vNode.directiveManager;
11398
+ const trueBind = manager?.findBindDirective('true-value');
11399
+ const falseBind = manager?.findBindDirective('false-value');
11400
+ if (!trueBind && !falseBind) {
11401
+ return undefined;
11402
+ }
11403
+ return {
11404
+ trueValue: trueBind ? trueBind.evaluate() : true,
11405
+ falseValue: falseBind ? falseBind.evaluate() : false,
11406
+ };
11407
+ }
11263
11408
  /**
11264
11409
  * Applies modifiers to the input value.
11265
11410
  * @param value The value to process.