@ngutil/aria 0.0.56 → 0.0.57
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/esm2022/ui-state/abstract.mjs +2 -3
- package/esm2022/ui-state/selector.mjs +308 -0
- package/esm2022/ui-state/ui-state.mjs +9 -21
- package/fesm2022/ngutil-aria.mjs +316 -22
- package/fesm2022/ngutil-aria.mjs.map +1 -1
- package/package.json +3 -3
- package/ui-state/selector.d.ts +60 -0
- package/ui-state/ui-state.d.ts +2 -2
package/fesm2022/ngutil-aria.mjs
CHANGED
|
@@ -562,6 +562,314 @@ function direction(prev, curr) {
|
|
|
562
562
|
// const w = svc.watch(document.createElement("div"), DragAndDrop)
|
|
563
563
|
function noop() { }
|
|
564
564
|
|
|
565
|
+
const COMPILE_CACHE = {};
|
|
566
|
+
function compile(selector) {
|
|
567
|
+
return (COMPILE_CACHE[selector] ??= _compile(parse(selector)));
|
|
568
|
+
}
|
|
569
|
+
class Cursor {
|
|
570
|
+
get ch() {
|
|
571
|
+
return this.data[this.position];
|
|
572
|
+
}
|
|
573
|
+
constructor(data) {
|
|
574
|
+
this.data = data;
|
|
575
|
+
this.position = 0;
|
|
576
|
+
}
|
|
577
|
+
inc(value = 1) {
|
|
578
|
+
this.position += value;
|
|
579
|
+
return this;
|
|
580
|
+
}
|
|
581
|
+
eatWs() {
|
|
582
|
+
let end = this.position;
|
|
583
|
+
while (end < this.data.length && /[ \r\n\t]/.test(this.data[end])) {
|
|
584
|
+
end++;
|
|
585
|
+
}
|
|
586
|
+
this.position = end;
|
|
587
|
+
return this;
|
|
588
|
+
}
|
|
589
|
+
is(ch) {
|
|
590
|
+
if (ch.length === 1) {
|
|
591
|
+
return this.ch === ch;
|
|
592
|
+
}
|
|
593
|
+
const begin = this.position;
|
|
594
|
+
const end = begin + ch.length;
|
|
595
|
+
return this.data.substring(begin, end) === ch;
|
|
596
|
+
}
|
|
597
|
+
eof() {
|
|
598
|
+
return this.position >= this.data.length;
|
|
599
|
+
}
|
|
600
|
+
set(position) {
|
|
601
|
+
this.position = position;
|
|
602
|
+
return this;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* expression:
|
|
607
|
+
* - "*": any
|
|
608
|
+
* - "name without dot": top level: eg. "busy" or "disabled", this is equal to "busy.*"
|
|
609
|
+
* - "name with dot": nested: eg. "busy.self" or "busy.loading"
|
|
610
|
+
* - negate: "!busy", "!busy.*", "!busy.save"
|
|
611
|
+
* - OR: "busy.* || !disabled.*"
|
|
612
|
+
* - AND: "busy.* && !disabled.*"
|
|
613
|
+
* - GROUP: "(busy || disabled) && !readonly"
|
|
614
|
+
* - Shorted of multiple source of same base: "busy{load,save}", if one of load or save is true, the result is true
|
|
615
|
+
*/
|
|
616
|
+
function parse(selector) {
|
|
617
|
+
const cursor = new Cursor(selector);
|
|
618
|
+
const res = expression(cursor.eatWs());
|
|
619
|
+
if (res == null) {
|
|
620
|
+
throw new Error(`invalid selector: ${selector}`);
|
|
621
|
+
}
|
|
622
|
+
if (!cursor.eof()) {
|
|
623
|
+
throw new Error(`unexpected charcter: ${selector[res.end]} at ${res.end}`);
|
|
624
|
+
}
|
|
625
|
+
return res;
|
|
626
|
+
}
|
|
627
|
+
function expression(cursor, skip) {
|
|
628
|
+
return binary(cursor) || leftExpr(cursor);
|
|
629
|
+
}
|
|
630
|
+
function leftExpr(cursor) {
|
|
631
|
+
const begin = cursor.position;
|
|
632
|
+
const left = unary(cursor) || group(cursor) || load(cursor);
|
|
633
|
+
if (left != null) {
|
|
634
|
+
return left;
|
|
635
|
+
}
|
|
636
|
+
cursor.set(begin);
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
639
|
+
function group(cursor) {
|
|
640
|
+
const begin = cursor.position;
|
|
641
|
+
if (cursor.is("(")) {
|
|
642
|
+
const expr = expression(cursor.inc().eatWs());
|
|
643
|
+
if (cursor.eatWs().is(")")) {
|
|
644
|
+
cursor.inc();
|
|
645
|
+
return binary(cursor.eatWs(), expr) || expr;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
cursor.set(begin);
|
|
649
|
+
return null;
|
|
650
|
+
}
|
|
651
|
+
function binary(cursor, left = null) {
|
|
652
|
+
const begin = cursor.position;
|
|
653
|
+
left = left ?? leftExpr(cursor);
|
|
654
|
+
if (left != null) {
|
|
655
|
+
cursor.eatWs();
|
|
656
|
+
const result = and(left, cursor) || or(left, cursor);
|
|
657
|
+
if (result != null) {
|
|
658
|
+
return result;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
cursor.set(begin);
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
function and(left, cursor) {
|
|
665
|
+
if (cursor.is("&&")) {
|
|
666
|
+
cursor.inc(2);
|
|
667
|
+
const right = expression(cursor.eatWs());
|
|
668
|
+
if (right == null) {
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
return { type: 5 /* TokenType.And */, left, right, begin: left.begin, end: cursor.position };
|
|
672
|
+
}
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
function or(left, cursor) {
|
|
676
|
+
if (cursor.is("||")) {
|
|
677
|
+
cursor.inc(2);
|
|
678
|
+
const right = expression(cursor.eatWs());
|
|
679
|
+
if (right == null) {
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
return { type: 4 /* TokenType.Or */, left, right, begin: left.begin, end: cursor.position };
|
|
683
|
+
}
|
|
684
|
+
return null;
|
|
685
|
+
}
|
|
686
|
+
function unary(cursor) {
|
|
687
|
+
const begin = cursor.position;
|
|
688
|
+
if (cursor.is("!")) {
|
|
689
|
+
const expr = leftExpr(cursor.inc().eatWs());
|
|
690
|
+
if (expr != null) {
|
|
691
|
+
return { type: 3 /* TokenType.Negate */, value: expr, begin, end: cursor.position };
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
cursor.set(begin);
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
function load(cursor) {
|
|
698
|
+
cursor.eatWs();
|
|
699
|
+
const _any = any(cursor);
|
|
700
|
+
if (_any != null) {
|
|
701
|
+
return _any;
|
|
702
|
+
}
|
|
703
|
+
const base = name(cursor);
|
|
704
|
+
if (base == null) {
|
|
705
|
+
return null;
|
|
706
|
+
}
|
|
707
|
+
cursor.eatWs();
|
|
708
|
+
const sub = loadSingle(cursor) || loadMulti(cursor);
|
|
709
|
+
if (sub == null) {
|
|
710
|
+
return base;
|
|
711
|
+
}
|
|
712
|
+
else if (Array.isArray(sub)) {
|
|
713
|
+
return {
|
|
714
|
+
type: 8 /* TokenType.MultiSubscript */,
|
|
715
|
+
base,
|
|
716
|
+
subscripts: sub,
|
|
717
|
+
begin: base.begin,
|
|
718
|
+
end: sub[sub.length - 1].end
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
return { type: 7 /* TokenType.Subscript */, base, subscript: sub, begin: base.begin, end: sub.end };
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
function loadSingle(cursor) {
|
|
726
|
+
const begin = cursor.position;
|
|
727
|
+
if (cursor.is(".")) {
|
|
728
|
+
cursor.inc().eatWs();
|
|
729
|
+
const prop = any(cursor) || name(cursor);
|
|
730
|
+
if (prop != null) {
|
|
731
|
+
return prop;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
cursor.set(begin);
|
|
735
|
+
return null;
|
|
736
|
+
}
|
|
737
|
+
function loadMulti(cursor) {
|
|
738
|
+
const begin = cursor.position;
|
|
739
|
+
if (cursor.is("{")) {
|
|
740
|
+
const names = [];
|
|
741
|
+
let entry = null;
|
|
742
|
+
cursor.inc().eatWs();
|
|
743
|
+
while ((entry = name(cursor))) {
|
|
744
|
+
names.push(entry);
|
|
745
|
+
cursor.eatWs();
|
|
746
|
+
if (cursor.is(",")) {
|
|
747
|
+
cursor.inc();
|
|
748
|
+
}
|
|
749
|
+
cursor.eatWs();
|
|
750
|
+
if (cursor.is("}")) {
|
|
751
|
+
if (names.length === 0) {
|
|
752
|
+
throw new Error("expected name");
|
|
753
|
+
}
|
|
754
|
+
cursor.inc();
|
|
755
|
+
return names;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
cursor.set(begin);
|
|
760
|
+
return null;
|
|
761
|
+
}
|
|
762
|
+
function name(cursor) {
|
|
763
|
+
const begin = cursor.position;
|
|
764
|
+
while (!cursor.eof() && isNameCh(cursor.ch)) {
|
|
765
|
+
cursor.inc();
|
|
766
|
+
}
|
|
767
|
+
if (cursor.position > begin) {
|
|
768
|
+
return { type: 2 /* TokenType.Name */, begin, end: cursor.position, value: cursor.data.slice(begin, cursor.position) };
|
|
769
|
+
}
|
|
770
|
+
cursor.set(begin);
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
function isNameCh(ch) {
|
|
774
|
+
return /[^.,{}()!\s&|]/.test(ch);
|
|
775
|
+
}
|
|
776
|
+
function any(cursor) {
|
|
777
|
+
if (cursor.is("*")) {
|
|
778
|
+
const begin = cursor.position;
|
|
779
|
+
cursor.inc();
|
|
780
|
+
return { type: 1 /* TokenType.Any */, begin, end: cursor.position };
|
|
781
|
+
}
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
function _compile(ast, parent) {
|
|
785
|
+
switch (ast.type) {
|
|
786
|
+
case 1 /* TokenType.Any */:
|
|
787
|
+
return compileAny(ast, parent);
|
|
788
|
+
case 7 /* TokenType.Subscript */:
|
|
789
|
+
return compileSubscript(ast, parent);
|
|
790
|
+
case 8 /* TokenType.MultiSubscript */:
|
|
791
|
+
return compileMultiSubscript(ast, parent);
|
|
792
|
+
case 2 /* TokenType.Name */:
|
|
793
|
+
return compileName(ast, parent);
|
|
794
|
+
case 3 /* TokenType.Negate */:
|
|
795
|
+
return compileNot(_compile(ast.value, parent));
|
|
796
|
+
case 4 /* TokenType.Or */:
|
|
797
|
+
return compileOr(_compile(ast.left, parent), _compile(ast.right, parent));
|
|
798
|
+
case 5 /* TokenType.And */:
|
|
799
|
+
return compileAnd(_compile(ast.left, parent), _compile(ast.right, parent));
|
|
800
|
+
}
|
|
801
|
+
return () => false;
|
|
802
|
+
}
|
|
803
|
+
function compileAny(ast, parent) {
|
|
804
|
+
if (parent) {
|
|
805
|
+
return v => {
|
|
806
|
+
if (v[parent] == null) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
return Object.values(v[parent]).some(v => v === true);
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
return v => {
|
|
814
|
+
for (const entry of Object.values(v)) {
|
|
815
|
+
if (Object.values(entry).some(v => v === true)) {
|
|
816
|
+
return true;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return false;
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
function compileSubscript(ast, parent) {
|
|
824
|
+
parent ??= ast.base.value;
|
|
825
|
+
if (ast.subscript.type === 1 /* TokenType.Any */) {
|
|
826
|
+
return compileAny(ast.subscript, parent);
|
|
827
|
+
}
|
|
828
|
+
if (ast.subscript.type === 2 /* TokenType.Name */) {
|
|
829
|
+
return compileName(ast.subscript, parent);
|
|
830
|
+
}
|
|
831
|
+
return () => false;
|
|
832
|
+
}
|
|
833
|
+
function compileMultiSubscript(ast, parent) {
|
|
834
|
+
parent ??= ast.base.value;
|
|
835
|
+
const values = ast.subscripts.map(v => compileSubscript({ type: 7 /* TokenType.Subscript */, base: ast.base, subscript: v, begin: v.begin, end: v.end }, parent));
|
|
836
|
+
if (values.length === 1) {
|
|
837
|
+
return values[0];
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
let result = values[0];
|
|
841
|
+
for (let i = 1; i < values.length; i++) {
|
|
842
|
+
result = compileOr(result, values[i]);
|
|
843
|
+
}
|
|
844
|
+
return result;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
function compileName(ast, parent) {
|
|
848
|
+
if (parent) {
|
|
849
|
+
return v => {
|
|
850
|
+
if (v[parent] == null) {
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
return !!v[parent][ast.value];
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
else {
|
|
857
|
+
return v => {
|
|
858
|
+
const many = v[ast.value];
|
|
859
|
+
return many != null && Object.values(many).some(v => v === true);
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
function compileNot(compiled) {
|
|
864
|
+
return v => !compiled(v);
|
|
865
|
+
}
|
|
866
|
+
function compileOr(left, right) {
|
|
867
|
+
return v => left(v) || right(v);
|
|
868
|
+
}
|
|
869
|
+
function compileAnd(left, right) {
|
|
870
|
+
return v => left(v) && right(v);
|
|
871
|
+
}
|
|
872
|
+
|
|
565
873
|
var _a;
|
|
566
874
|
class UiState {
|
|
567
875
|
constructor() {
|
|
@@ -616,27 +924,14 @@ class UiState {
|
|
|
616
924
|
if (entry[source] !== value) {
|
|
617
925
|
this.#self.set({ ...current, [name]: { ...entry, [source]: value } });
|
|
618
926
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
927
|
+
// TODO: maybe some option to propagate to root
|
|
928
|
+
// const root = this.root
|
|
929
|
+
// if (source !== "self" && root !== this) {
|
|
930
|
+
// root.set(name, value, source)
|
|
931
|
+
// }
|
|
623
932
|
}
|
|
624
|
-
is(
|
|
625
|
-
|
|
626
|
-
const current = this.value();
|
|
627
|
-
return current[name] ?? false;
|
|
628
|
-
}
|
|
629
|
-
else if (selector.includes(",")) {
|
|
630
|
-
const merged = this.merged();
|
|
631
|
-
return selector
|
|
632
|
-
.split(/\s*,\s*/)
|
|
633
|
-
.map(v => merged[name]?.[v] ?? false)
|
|
634
|
-
.some(v => v);
|
|
635
|
-
}
|
|
636
|
-
else {
|
|
637
|
-
const merged = this.merged();
|
|
638
|
-
return merged[name]?.[selector] ?? false;
|
|
639
|
-
}
|
|
933
|
+
is(selector = "*") {
|
|
934
|
+
return compile(selector)(this.merged());
|
|
640
935
|
}
|
|
641
936
|
intercept(name, source) {
|
|
642
937
|
return (src) => this.wrap(src, name, source);
|
|
@@ -665,7 +960,7 @@ class AbstractUiState {
|
|
|
665
960
|
this.yes = computed(() => {
|
|
666
961
|
const when = this.when();
|
|
667
962
|
if (when !== NOTSET) {
|
|
668
|
-
return this.state.is(this.name
|
|
963
|
+
return this.state.is(`${this.name}.self || (${when})`);
|
|
669
964
|
}
|
|
670
965
|
return this.state.is(this.name);
|
|
671
966
|
});
|
|
@@ -675,7 +970,6 @@ class AbstractUiState {
|
|
|
675
970
|
if (input !== NOTSET) {
|
|
676
971
|
this.state.set(name, !!coerceBoolAttr(input));
|
|
677
972
|
}
|
|
678
|
-
this.yes();
|
|
679
973
|
}, { allowSignalWrites: true });
|
|
680
974
|
}
|
|
681
975
|
set(value, source) {
|