@mintjamsinc/ichigojs 0.1.59 → 0.1.60
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 +240 -1
- package/dist/ichigo.cjs.map +1 -1
- package/dist/ichigo.esm.js +240 -1
- 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 +240 -1
- package/dist/ichigo.umd.js.map +1 -1
- package/dist/ichigo.umd.min.js +1 -1
- package/dist/types/ichigo/directives/StandardDirectiveName.d.ts +3 -1
- package/dist/types/ichigo/directives/VFocusDirective.d.ts +87 -0
- package/package.json +1 -1
package/dist/ichigo.esm.js
CHANGED
|
@@ -171,6 +171,8 @@ var StandardDirectiveName;
|
|
|
171
171
|
StandardDirectiveName["V_HTML"] = "v-html";
|
|
172
172
|
/** Text content directive. */
|
|
173
173
|
StandardDirectiveName["V_TEXT"] = "v-text";
|
|
174
|
+
/** Focus management directive. */
|
|
175
|
+
StandardDirectiveName["V_FOCUS"] = "v-focus";
|
|
174
176
|
})(StandardDirectiveName || (StandardDirectiveName = {}));
|
|
175
177
|
|
|
176
178
|
// This file was generated. Do not modify manually!
|
|
@@ -12379,6 +12381,235 @@ class VTextDirective {
|
|
|
12379
12381
|
}
|
|
12380
12382
|
}
|
|
12381
12383
|
|
|
12384
|
+
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
|
12385
|
+
/**
|
|
12386
|
+
* Directive for managing focus on form elements.
|
|
12387
|
+
*
|
|
12388
|
+
* Usage:
|
|
12389
|
+
* <input v-focus> Focus once on mount.
|
|
12390
|
+
* <input v-focus.select> Focus + select all on mount.
|
|
12391
|
+
* <input v-focus="isOpen"> Focus when expression transitions from falsy to truthy.
|
|
12392
|
+
* <input v-focus.select="isOpen"> Conditional focus + select all.
|
|
12393
|
+
* <input v-focus.cursor-end="isOpen"> Conditional focus + place caret at end.
|
|
12394
|
+
*
|
|
12395
|
+
* Behavior notes:
|
|
12396
|
+
* - Without an expression, the element is focused exactly once after mount.
|
|
12397
|
+
* - With an expression, focus fires only on the falsy -> truthy edge,
|
|
12398
|
+
* so the user is not repeatedly re-focused on every reactive update.
|
|
12399
|
+
* - If the value is already truthy on mount, the element is focused.
|
|
12400
|
+
* - Focus is deferred via requestAnimationFrame so that elements which
|
|
12401
|
+
* become visible just before this directive runs (e.g. inside v-if /
|
|
12402
|
+
* display:none containers) can still receive focus reliably.
|
|
12403
|
+
*/
|
|
12404
|
+
class VFocusDirective {
|
|
12405
|
+
/**
|
|
12406
|
+
* The virtual node to which this directive is applied.
|
|
12407
|
+
*/
|
|
12408
|
+
#vNode;
|
|
12409
|
+
/**
|
|
12410
|
+
* Optional expression evaluator. When absent, the directive focuses once on mount.
|
|
12411
|
+
*/
|
|
12412
|
+
#evaluator;
|
|
12413
|
+
/**
|
|
12414
|
+
* Modifiers extracted from the directive name (e.g. "select", "cursor-end").
|
|
12415
|
+
*/
|
|
12416
|
+
#modifiers = new Set();
|
|
12417
|
+
/**
|
|
12418
|
+
* Last evaluated boolean value, used for falsy -> truthy edge detection.
|
|
12419
|
+
*/
|
|
12420
|
+
#previousValue = false;
|
|
12421
|
+
/**
|
|
12422
|
+
* @param context The context for parsing the directive.
|
|
12423
|
+
*/
|
|
12424
|
+
constructor(context) {
|
|
12425
|
+
this.#vNode = context.vNode;
|
|
12426
|
+
// Extract modifiers from the directive name
|
|
12427
|
+
// e.g., "v-focus.select" -> modifiers = {"select"}
|
|
12428
|
+
const attrName = context.attribute.name;
|
|
12429
|
+
if (attrName.startsWith(StandardDirectiveName.V_FOCUS + '.')) {
|
|
12430
|
+
const parts = attrName.split('.');
|
|
12431
|
+
parts.slice(1).forEach(mod => this.#modifiers.add(mod));
|
|
12432
|
+
}
|
|
12433
|
+
// Parse the expression and create the evaluator (optional)
|
|
12434
|
+
const expression = context.attribute.value;
|
|
12435
|
+
if (expression) {
|
|
12436
|
+
if (!context.vNode.bindings) {
|
|
12437
|
+
throw new Error('VFocusDirective requires bindings when an expression is provided');
|
|
12438
|
+
}
|
|
12439
|
+
this.#evaluator = ExpressionEvaluator.create(expression, context.vNode.bindings, context.vNode.vApplication.functionDependencies);
|
|
12440
|
+
}
|
|
12441
|
+
// Remove the directive attribute from the element
|
|
12442
|
+
this.#vNode.node.removeAttribute(context.attribute.name);
|
|
12443
|
+
}
|
|
12444
|
+
/**
|
|
12445
|
+
* @inheritdoc
|
|
12446
|
+
*/
|
|
12447
|
+
get name() {
|
|
12448
|
+
return StandardDirectiveName.V_FOCUS;
|
|
12449
|
+
}
|
|
12450
|
+
/**
|
|
12451
|
+
* @inheritdoc
|
|
12452
|
+
*/
|
|
12453
|
+
get vNode() {
|
|
12454
|
+
return this.#vNode;
|
|
12455
|
+
}
|
|
12456
|
+
/**
|
|
12457
|
+
* @inheritdoc
|
|
12458
|
+
*/
|
|
12459
|
+
get needsAnchor() {
|
|
12460
|
+
return false;
|
|
12461
|
+
}
|
|
12462
|
+
/**
|
|
12463
|
+
* @inheritdoc
|
|
12464
|
+
*/
|
|
12465
|
+
get bindingsPreparer() {
|
|
12466
|
+
return undefined;
|
|
12467
|
+
}
|
|
12468
|
+
/**
|
|
12469
|
+
* @inheritdoc
|
|
12470
|
+
*/
|
|
12471
|
+
get domUpdater() {
|
|
12472
|
+
// Without an expression, there is nothing reactive to track.
|
|
12473
|
+
if (!this.#evaluator) {
|
|
12474
|
+
return undefined;
|
|
12475
|
+
}
|
|
12476
|
+
const identifiers = this.#evaluator.dependentIdentifiers;
|
|
12477
|
+
const evaluator = this.#evaluator;
|
|
12478
|
+
const focusElement = () => this.#focus();
|
|
12479
|
+
const updater = {
|
|
12480
|
+
get dependentIdentifiers() {
|
|
12481
|
+
return identifiers;
|
|
12482
|
+
},
|
|
12483
|
+
applyToDOM: () => {
|
|
12484
|
+
const value = evaluator.evaluateAsBoolean();
|
|
12485
|
+
const previous = this.#previousValue;
|
|
12486
|
+
this.#previousValue = value;
|
|
12487
|
+
// Edge: falsy -> truthy
|
|
12488
|
+
if (!previous && value) {
|
|
12489
|
+
focusElement();
|
|
12490
|
+
}
|
|
12491
|
+
}
|
|
12492
|
+
};
|
|
12493
|
+
return updater;
|
|
12494
|
+
}
|
|
12495
|
+
/**
|
|
12496
|
+
* @inheritdoc
|
|
12497
|
+
*/
|
|
12498
|
+
get templatize() {
|
|
12499
|
+
return false;
|
|
12500
|
+
}
|
|
12501
|
+
/**
|
|
12502
|
+
* @inheritdoc
|
|
12503
|
+
*/
|
|
12504
|
+
get dependentIdentifiers() {
|
|
12505
|
+
return this.#evaluator?.dependentIdentifiers ?? [];
|
|
12506
|
+
}
|
|
12507
|
+
/**
|
|
12508
|
+
* @inheritdoc
|
|
12509
|
+
*/
|
|
12510
|
+
get onMount() {
|
|
12511
|
+
return undefined;
|
|
12512
|
+
}
|
|
12513
|
+
/**
|
|
12514
|
+
* @inheritdoc
|
|
12515
|
+
*/
|
|
12516
|
+
get onMounted() {
|
|
12517
|
+
return () => {
|
|
12518
|
+
if (!this.#evaluator) {
|
|
12519
|
+
// Unconditional: focus once on mount.
|
|
12520
|
+
this.#focus();
|
|
12521
|
+
return;
|
|
12522
|
+
}
|
|
12523
|
+
// Conditional: seed previous value and focus if already truthy on mount.
|
|
12524
|
+
const value = this.#evaluator.evaluateAsBoolean();
|
|
12525
|
+
this.#previousValue = value;
|
|
12526
|
+
if (value) {
|
|
12527
|
+
this.#focus();
|
|
12528
|
+
}
|
|
12529
|
+
};
|
|
12530
|
+
}
|
|
12531
|
+
/**
|
|
12532
|
+
* @inheritdoc
|
|
12533
|
+
*/
|
|
12534
|
+
get onUpdate() {
|
|
12535
|
+
return undefined;
|
|
12536
|
+
}
|
|
12537
|
+
/**
|
|
12538
|
+
* @inheritdoc
|
|
12539
|
+
*/
|
|
12540
|
+
get onUpdated() {
|
|
12541
|
+
return undefined;
|
|
12542
|
+
}
|
|
12543
|
+
/**
|
|
12544
|
+
* @inheritdoc
|
|
12545
|
+
*/
|
|
12546
|
+
get onUnmount() {
|
|
12547
|
+
return undefined;
|
|
12548
|
+
}
|
|
12549
|
+
/**
|
|
12550
|
+
* @inheritdoc
|
|
12551
|
+
*/
|
|
12552
|
+
get onUnmounted() {
|
|
12553
|
+
return undefined;
|
|
12554
|
+
}
|
|
12555
|
+
/**
|
|
12556
|
+
* @inheritdoc
|
|
12557
|
+
*/
|
|
12558
|
+
destroy() {
|
|
12559
|
+
// No specific cleanup needed for this directive.
|
|
12560
|
+
}
|
|
12561
|
+
/**
|
|
12562
|
+
* Focuses the element, applying any modifier-driven post-focus behavior.
|
|
12563
|
+
* Deferred via requestAnimationFrame so that elements transitioning out
|
|
12564
|
+
* of display:none (e.g. inside v-if) can receive focus reliably.
|
|
12565
|
+
*/
|
|
12566
|
+
#focus() {
|
|
12567
|
+
const element = this.#vNode.node;
|
|
12568
|
+
if (!element || typeof element.focus !== 'function') {
|
|
12569
|
+
return;
|
|
12570
|
+
}
|
|
12571
|
+
const applyModifiers = () => this.#applyModifiers();
|
|
12572
|
+
requestAnimationFrame(() => {
|
|
12573
|
+
// The element may have been unmounted between scheduling and execution.
|
|
12574
|
+
if (!element.isConnected) {
|
|
12575
|
+
return;
|
|
12576
|
+
}
|
|
12577
|
+
element.focus();
|
|
12578
|
+
applyModifiers();
|
|
12579
|
+
});
|
|
12580
|
+
}
|
|
12581
|
+
/**
|
|
12582
|
+
* Applies modifier-driven behavior after focus.
|
|
12583
|
+
*/
|
|
12584
|
+
#applyModifiers() {
|
|
12585
|
+
const element = this.#vNode.node;
|
|
12586
|
+
if (this.#modifiers.has('select')) {
|
|
12587
|
+
const inputEl = element;
|
|
12588
|
+
if (typeof inputEl.select === 'function') {
|
|
12589
|
+
try {
|
|
12590
|
+
inputEl.select();
|
|
12591
|
+
}
|
|
12592
|
+
catch {
|
|
12593
|
+
// Some input types (e.g. number) reject select(); ignore.
|
|
12594
|
+
}
|
|
12595
|
+
}
|
|
12596
|
+
return;
|
|
12597
|
+
}
|
|
12598
|
+
if (this.#modifiers.has('cursor-end')) {
|
|
12599
|
+
const inputEl = element;
|
|
12600
|
+
if (typeof inputEl.setSelectionRange === 'function') {
|
|
12601
|
+
const len = (inputEl.value ?? '').length;
|
|
12602
|
+
try {
|
|
12603
|
+
inputEl.setSelectionRange(len, len);
|
|
12604
|
+
}
|
|
12605
|
+
catch {
|
|
12606
|
+
// Some input types (e.g. number) do not support selection ranges; ignore.
|
|
12607
|
+
}
|
|
12608
|
+
}
|
|
12609
|
+
}
|
|
12610
|
+
}
|
|
12611
|
+
}
|
|
12612
|
+
|
|
12382
12613
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
|
12383
12614
|
/**
|
|
12384
12615
|
* The directive parser for standard directives.
|
|
@@ -12420,7 +12651,10 @@ class VStandardDirectiveParser {
|
|
|
12420
12651
|
// v-html
|
|
12421
12652
|
context.attribute.name === StandardDirectiveName.V_HTML ||
|
|
12422
12653
|
// v-text
|
|
12423
|
-
context.attribute.name === StandardDirectiveName.V_TEXT
|
|
12654
|
+
context.attribute.name === StandardDirectiveName.V_TEXT ||
|
|
12655
|
+
// v-focus, v-focus.<modifier>
|
|
12656
|
+
context.attribute.name === StandardDirectiveName.V_FOCUS ||
|
|
12657
|
+
context.attribute.name.startsWith(StandardDirectiveName.V_FOCUS + ".")) {
|
|
12424
12658
|
return true;
|
|
12425
12659
|
}
|
|
12426
12660
|
return false;
|
|
@@ -12484,6 +12718,11 @@ class VStandardDirectiveParser {
|
|
|
12484
12718
|
if (context.attribute.name === StandardDirectiveName.V_TEXT) {
|
|
12485
12719
|
return new VTextDirective(context);
|
|
12486
12720
|
}
|
|
12721
|
+
// v-focus, v-focus.<modifier>
|
|
12722
|
+
if (context.attribute.name === StandardDirectiveName.V_FOCUS ||
|
|
12723
|
+
context.attribute.name.startsWith(StandardDirectiveName.V_FOCUS + ".")) {
|
|
12724
|
+
return new VFocusDirective(context);
|
|
12725
|
+
}
|
|
12487
12726
|
throw new Error(`The attribute "${context.attribute.name}" cannot be parsed by ${this.name}.`);
|
|
12488
12727
|
}
|
|
12489
12728
|
}
|