@memberjunction/ng-ui-components 6.2.0-edge.0 → 6.2.0-edge.1

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.
Files changed (81) hide show
  1. package/README.md +35 -9
  2. package/dist/lib/a11y/named-control.base.d.ts +91 -0
  3. package/dist/lib/a11y/named-control.base.d.ts.map +1 -0
  4. package/dist/lib/a11y/named-control.base.js +121 -0
  5. package/dist/lib/a11y/named-control.base.js.map +1 -0
  6. package/dist/lib/a11y/unnamed-control-guard.d.ts +52 -0
  7. package/dist/lib/a11y/unnamed-control-guard.d.ts.map +1 -0
  8. package/dist/lib/a11y/unnamed-control-guard.js +94 -0
  9. package/dist/lib/a11y/unnamed-control-guard.js.map +1 -0
  10. package/dist/lib/accordion/accordion.component.d.ts +16 -4
  11. package/dist/lib/accordion/accordion.component.d.ts.map +1 -1
  12. package/dist/lib/accordion/accordion.component.js +36 -12
  13. package/dist/lib/accordion/accordion.component.js.map +1 -1
  14. package/dist/lib/applied-filters/applied-filters.component.js.map +1 -1
  15. package/dist/lib/button/button.directive.d.ts +34 -6
  16. package/dist/lib/button/button.directive.d.ts.map +1 -1
  17. package/dist/lib/button/button.directive.js +85 -25
  18. package/dist/lib/button/button.directive.js.map +1 -1
  19. package/dist/lib/card-grid/card-grid.component.d.ts +3 -1
  20. package/dist/lib/card-grid/card-grid.component.d.ts.map +1 -1
  21. package/dist/lib/card-grid/card-grid.component.js +13 -9
  22. package/dist/lib/card-grid/card-grid.component.js.map +1 -1
  23. package/dist/lib/clickable/clickable.directive.d.ts +11 -3
  24. package/dist/lib/clickable/clickable.directive.d.ts.map +1 -1
  25. package/dist/lib/clickable/clickable.directive.js +25 -5
  26. package/dist/lib/clickable/clickable.directive.js.map +1 -1
  27. package/dist/lib/combobox/combobox.component.d.ts +44 -3
  28. package/dist/lib/combobox/combobox.component.d.ts.map +1 -1
  29. package/dist/lib/combobox/combobox.component.js +135 -51
  30. package/dist/lib/combobox/combobox.component.js.map +1 -1
  31. package/dist/lib/confirm-dialog/confirm-dialog.component.d.ts +6 -0
  32. package/dist/lib/confirm-dialog/confirm-dialog.component.d.ts.map +1 -1
  33. package/dist/lib/confirm-dialog/confirm-dialog.component.js +16 -4
  34. package/dist/lib/confirm-dialog/confirm-dialog.component.js.map +1 -1
  35. package/dist/lib/datepicker/datepicker.component.d.ts +25 -2
  36. package/dist/lib/datepicker/datepicker.component.d.ts.map +1 -1
  37. package/dist/lib/datepicker/datepicker.component.js +98 -42
  38. package/dist/lib/datepicker/datepicker.component.js.map +1 -1
  39. package/dist/lib/dialog/dialog.component.d.ts +4 -0
  40. package/dist/lib/dialog/dialog.component.d.ts.map +1 -1
  41. package/dist/lib/dialog/dialog.component.js +12 -4
  42. package/dist/lib/dialog/dialog.component.js.map +1 -1
  43. package/dist/lib/dialog/dialog.service.js.map +1 -1
  44. package/dist/lib/dropdown/dropdown.component.d.ts +19 -44
  45. package/dist/lib/dropdown/dropdown.component.d.ts.map +1 -1
  46. package/dist/lib/dropdown/dropdown.component.js +37 -76
  47. package/dist/lib/dropdown/dropdown.component.js.map +1 -1
  48. package/dist/lib/dropdown/dropdown.scss +0 -16
  49. package/dist/lib/filter-panel/filter-panel.component.d.ts +8 -0
  50. package/dist/lib/filter-panel/filter-panel.component.d.ts.map +1 -1
  51. package/dist/lib/filter-panel/filter-panel.component.js +25 -9
  52. package/dist/lib/filter-panel/filter-panel.component.js.map +1 -1
  53. package/dist/lib/numeric-input/numeric-input.component.d.ts +15 -1
  54. package/dist/lib/numeric-input/numeric-input.component.d.ts.map +1 -1
  55. package/dist/lib/numeric-input/numeric-input.component.js +36 -9
  56. package/dist/lib/numeric-input/numeric-input.component.js.map +1 -1
  57. package/dist/lib/page-search/page-search.component.d.ts +32 -3
  58. package/dist/lib/page-search/page-search.component.d.ts.map +1 -1
  59. package/dist/lib/page-search/page-search.component.js +68 -12
  60. package/dist/lib/page-search/page-search.component.js.map +1 -1
  61. package/dist/lib/switch/switch.component.d.ts +22 -1
  62. package/dist/lib/switch/switch.component.d.ts.map +1 -1
  63. package/dist/lib/switch/switch.component.js +50 -16
  64. package/dist/lib/switch/switch.component.js.map +1 -1
  65. package/dist/lib/tabs/tab-chrome-guard.d.ts +2 -0
  66. package/dist/lib/tabs/tab-chrome-guard.d.ts.map +1 -1
  67. package/dist/lib/tabs/tab-chrome-guard.js +5 -1
  68. package/dist/lib/tabs/tab-chrome-guard.js.map +1 -1
  69. package/dist/lib/window/window.component.d.ts +10 -0
  70. package/dist/lib/window/window.component.d.ts.map +1 -1
  71. package/dist/lib/window/window.component.js +27 -7
  72. package/dist/lib/window/window.component.js.map +1 -1
  73. package/dist/lib/workspace-tabs/workspace-tab-strip.component.d.ts +10 -0
  74. package/dist/lib/workspace-tabs/workspace-tab-strip.component.d.ts.map +1 -1
  75. package/dist/lib/workspace-tabs/workspace-tab-strip.component.js +27 -7
  76. package/dist/lib/workspace-tabs/workspace-tab-strip.component.js.map +1 -1
  77. package/dist/public-api.d.ts +2 -0
  78. package/dist/public-api.d.ts.map +1 -1
  79. package/dist/public-api.js +2 -0
  80. package/dist/public-api.js.map +1 -1
  81. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"filter-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/filter-panel/filter-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;;AAOvE,2DAA2D;AAC3D,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;AAE5D,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,IAAI,EAAE,eAAe,CAAC;IACtB,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IACtE,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kDAAkD;IAClD,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzF;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,2DAA2D;AAC3D,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBA0Ia,sBAAsB;IACxB,MAAM,EAAE,iBAAiB,EAAE,CAAM;IACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM;IACrC,SAAS,EAAE,OAAO,CAAQ;IAC1B,UAAU,EAAE,MAAM,CAAmB;IAEpC,YAAY,wCAA+C;IAC3D,KAAK,qBAA4B;IAEpC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAKlD,0EAA0E;IACnE,YAAY,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO;IAQnF,iFAAiF;IAC1E,WAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI;yCA5BpE,sBAAsB;2CAAtB,sBAAsB;CA2ClC"}
1
+ {"version":3,"file":"filter-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/filter-panel/filter-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;;AAOvE,2DAA2D;AAC3D,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;AAE5D,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,IAAI,EAAE,eAAe,CAAC;IACtB,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IACtE,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kDAAkD;IAClD,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzF;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,2DAA2D;AAC3D,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBA0Ia,sBAAsB;IACxB,MAAM,EAAE,iBAAiB,EAAE,CAAM;IACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM;IACrC,SAAS,EAAE,OAAO,CAAQ;IAC1B,UAAU,EAAE,MAAM,CAAmB;IAEpC,YAAY,wCAA+C;IAC3D,KAAK,qBAA4B;IAEpC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIrC,wCAAwC;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAKlD,wCAAwC;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAIlD,0EAA0E;IACnE,YAAY,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO;IAQnF,4CAA4C;IACrC,YAAY,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO;IAInF,iFAAiF;IAC1E,WAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAgB/E,2CAA2C;IACpC,WAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI;yCA5DpE,sBAAsB;2CAAtB,sBAAsB;CA+DlC"}
@@ -106,28 +106,40 @@ export class MJFilterPanelComponent {
106
106
  ResetLabel = 'Reset filters';
107
107
  ValuesChange = new EventEmitter();
108
108
  Reset = new EventEmitter();
109
- getValue(key) {
109
+ GetValue(key) {
110
110
  return this.Values?.[key];
111
111
  }
112
- setValue(key, value) {
112
+ /** @deprecated Use {@link GetValue}. */
113
+ getValue(key) {
114
+ return this.GetValue(key);
115
+ }
116
+ SetValue(key, value) {
113
117
  this.Values = { ...this.Values, [key]: value };
114
118
  this.ValuesChange.emit(this.Values);
115
119
  }
120
+ /** @deprecated Use {@link SetValue}. */
121
+ setValue(key, value) {
122
+ return this.SetValue(key, value);
123
+ }
116
124
  /** Whether a chip option is currently active (handles single + multi). */
117
- isChipActive(field, optValue) {
125
+ IsChipActive(field, optValue) {
118
126
  if (field.multi) {
119
- const current = this.getValue(field.key);
127
+ const current = this.GetValue(field.key);
120
128
  return Array.isArray(current) && current.includes(optValue);
121
129
  }
122
- return this.getValue(field.key) === optValue;
130
+ return this.GetValue(field.key) === optValue;
131
+ }
132
+ /** @deprecated Use {@link IsChipActive}. */
133
+ isChipActive(field, optValue) {
134
+ return this.IsChipActive(field, optValue);
123
135
  }
124
136
  /** Chip click: replace (single-select) or toggle in/out of the array (multi). */
125
- onChipClick(field, optValue) {
137
+ OnChipClick(field, optValue) {
126
138
  if (!field.multi) {
127
- this.setValue(field.key, optValue);
139
+ this.SetValue(field.key, optValue);
128
140
  return;
129
141
  }
130
- const current = this.getValue(field.key);
142
+ const current = this.GetValue(field.key);
131
143
  const next = Array.isArray(current) ? [...current] : [];
132
144
  const idx = next.indexOf(optValue);
133
145
  if (idx >= 0) {
@@ -136,7 +148,11 @@ export class MJFilterPanelComponent {
136
148
  else {
137
149
  next.push(optValue);
138
150
  }
139
- this.setValue(field.key, next);
151
+ this.SetValue(field.key, next);
152
+ }
153
+ /** @deprecated Use {@link OnChipClick}. */
154
+ onChipClick(field, optValue) {
155
+ return this.OnChipClick(field, optValue);
140
156
  }
141
157
  static ɵfac = function MJFilterPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJFilterPanelComponent)(); };
142
158
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJFilterPanelComponent, selectors: [["mj-filter-panel"]], inputs: { Fields: "Fields", Values: "Values", ShowReset: "ShowReset", ResetLabel: "ResetLabel" }, outputs: { ValuesChange: "ValuesChange", Reset: "Reset" }, ngContentSelectors: _c0, decls: 6, vars: 1, consts: [[1, "mj-filter-panel"], [1, "mj-filter-panel-body"], [3, "Label", "Icon"], [1, "mj-filter-panel-footer"], ["type", "text", 1, "mj-filter-panel-text-input", 3, "value", "placeholder"], ["TextField", "text", "ValueField", "value", 3, "Data", "ValuePrimitive", "Filterable", "Placeholder", "ngModel"], [1, "mj-filter-panel-chip-group"], ["type", "text", 1, "mj-filter-panel-text-input", 3, "input", "value", "placeholder"], ["TextField", "text", "ValueField", "value", 3, "ngModelChange", "Data", "ValuePrimitive", "Filterable", "Placeholder", "ngModel"], [3, "Label", "Icon", "Active"], [3, "Clicked", "Label", "Icon", "Active"], ["type", "button", 1, "mj-filter-panel-reset", 3, "click"], [1, "fa-solid", "fa-rotate-left"]], template: function MJFilterPanelComponent_Template(rf, ctx) { if (rf & 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"filter-panel.component.js","sourceRoot":"","sources":["../../../src/lib/filter-panel/filter-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;;;;;;;;;IAwEhE,gCAK6D;IAA3D,6OAAS,kDAA8C,KAAC;IAL1D,iBAK6D;;;;IAD3D,AADA,2DAAmC,2CACI;;;;IAIzC,sCAQgD;IAA9C,mQAAiB,qCAA2B,KAAC;IAC/C,iBAAc;;;;IAFZ,AADA,AADA,AADA,AAHA,qEAA4B,wBAGL,qCACU,2CACM,0CACR;;;;IAO7B,0CAI4C;IAA1C,oRAAW,0CAA6B,KAAC;IAC3C,iBAAiB;;;;;IAFf,AADA,AADA,mCAAkB,6BACO,uDACgB;;;IAL/C,8BAAwC;IACtC,iHAOC;IACH,iBAAM;;;IARJ,cAOC;IAPD,iEAOC;;;IA/BT,0CAAmE;IAsB/D,AAZA,AARA,yFAAgB,yEAQI,iEAYH;IAarB,iBAAkB;;;;IAnCqB,AAAtB,sCAAqB,+BAA4B;IAChE,cAiCC;IAjCD,gDAAA,MAAM,oBAAN,UAAU,oBAAV,OAAO,UAiCN;;;;IAUH,AADF,8BAAoC,iBACyC;IAAvB,0LAAS,mBAAY,KAAC;IACxE,wBAAuC;IAAC,YAC1C;IACF,AADE,iBAAS,EACL;;;IAFsC,eAC1C;IAD0C,kDAC1C;;AAhFV;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AA2IH,MAAM,OAAO,sBAAsB;IACxB,MAAM,GAAwB,EAAE,CAAC;IACjC,MAAM,GAA4B,EAAE,CAAC;IACrC,SAAS,GAAY,IAAI,CAAC;IAC1B,UAAU,GAAW,eAAe,CAAC;IAEpC,YAAY,GAAG,IAAI,YAAY,EAA2B,CAAC;IAC3D,KAAK,GAAG,IAAI,YAAY,EAAQ,CAAC;IAEpC,QAAQ,CAAC,GAAW;QACzB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAEM,QAAQ,CAAC,GAAW,EAAE,KAAc;QACzC,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;QAC/C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,0EAA0E;IACnE,YAAY,CAAC,KAAwB,EAAE,QAA2B;QACvE,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACzC,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC;IAC/C,CAAC;IAED,iFAAiF;IAC1E,WAAW,CAAC,KAAwB,EAAE,QAA2B;QACtE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,IAAI,GAAwB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;gHA1CU,sBAAsB;6DAAtB,sBAAsB;;YApI7B,AADF,8BAA6B,aACO;YAChC,qGAqCC;YAGD,kBAAyB;YAC3B,iBAAM;YAEN,wFAAiB;YAOnB,iBAAM;;YAlDF,eAqCC;YArCD,yBAqCC;YAMH,eAMC;YAND,wCAMC;4BArDK,YAAY,EAAE,WAAW,kCAAE,mBAAmB,EAAE,qBAAqB,EAAE,sBAAsB;;iFAuI5F,sBAAsB;cA1IlC,SAAS;2BACE,iBAAiB,cACf,IAAI,WACP,CAAC,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,sBAAsB,CAAC,YAC9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDT;;kBAiFA,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBAEL,MAAM;;kBACN,MAAM;;kFAPI,sBAAsB","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { MJDropdownComponent } from '../dropdown/dropdown.component';\nimport { MJFilterChipComponent } from '../filter-chip/filter-chip.component';\nimport { MJFilterFieldComponent } from '../filter-field/filter-field.component';\n\n/** Field types supported natively by <mj-filter-panel>. */\nexport type FilterFieldType = 'text' | 'dropdown' | 'chips';\n\n/** Per-field config understood by <mj-filter-panel>. */\nexport interface FilterFieldConfig {\n /** State key in the Values record. */\n key: string;\n /** Field type — drives which widget is rendered. */\n type: FilterFieldType;\n /** Display label. */\n label: string;\n /** Optional Font Awesome icon class (e.g. 'fa-solid fa-folder'). */\n icon?: string;\n /** Placeholder for text inputs / dropdowns. */\n placeholder?: string;\n /** Dropdown options (when type === 'dropdown'). Each option needs text + value. */\n options?: { text: string; value: string | number | boolean | null }[];\n /** Whether the dropdown should show an internal search box. */\n filterable?: boolean;\n /** Chip-group options (when type === 'chips'). */\n chipOptions?: { text: string; value: string | number | boolean | null; icon?: string }[];\n /**\n * For `type === 'chips'` only. When `true`, the chip group is multi-select:\n * the field's value is an **array** of selected option values and clicking a\n * chip toggles it in/out. When absent/false (default), the group is\n * single-select (value is the chosen option value, click replaces).\n */\n multi?: boolean;\n}\n\n/** Option value type shared by dropdown + chip options. */\ntype FilterOptionValue = string | number | boolean | null;\n\n/**\n * mj-filter-panel — Single centralized filter panel for all dashboards.\n *\n * Config-driven: pass an array of `FilterFieldConfig` plus a `Values` record;\n * the panel renders each field using the appropriate widget (text input,\n * `<mj-dropdown>`, or chip group), keeps everything visually consistent, and\n * emits state changes via `(ValuesChange)`.\n *\n * For widgets not covered by the config schema (tree-dropdown, date pickers,\n * etc.), project `<mj-filter-field>` elements as content — they render below\n * the config-driven fields with identical chrome.\n *\n * Example:\n * ```html\n * <mj-filter-panel\n * [Fields]=\"filterFields\"\n * [(Values)]=\"filterValues\"\n * (Reset)=\"onReset()\">\n *\n * <!-- escape hatch for custom widgets -->\n * <mj-filter-field Label=\"Category\" Icon=\"fa-solid fa-folder\">\n * <mj-tree-dropdown ...></mj-tree-dropdown>\n * </mj-filter-field>\n * </mj-filter-panel>\n * ```\n */\n@Component({\n selector: 'mj-filter-panel',\n standalone: true,\n imports: [CommonModule, FormsModule, MJDropdownComponent, MJFilterChipComponent, MJFilterFieldComponent],\n template: `\n <div class=\"mj-filter-panel\">\n <div class=\"mj-filter-panel-body\">\n @for (field of Fields; track field.key) {\n <mj-filter-field [Label]=\"field.label\" [Icon]=\"field.icon ?? null\">\n @switch (field.type) {\n @case ('text') {\n <input\n type=\"text\"\n class=\"mj-filter-panel-text-input\"\n [value]=\"getValue(field.key) ?? ''\"\n [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"setValue(field.key, $any($event.target).value)\" />\n }\n @case ('dropdown') {\n <mj-dropdown\n [Data]=\"field.options ?? []\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n [Filterable]=\"!!field.filterable\"\n [Placeholder]=\"field.placeholder ?? ''\"\n [ngModel]=\"getValue(field.key)\"\n (ngModelChange)=\"setValue(field.key, $event)\">\n </mj-dropdown>\n }\n @case ('chips') {\n <div class=\"mj-filter-panel-chip-group\">\n @for (opt of field.chipOptions ?? []; track opt.value) {\n <mj-filter-chip\n [Label]=\"opt.text\"\n [Icon]=\"opt.icon ?? null\"\n [Active]=\"isChipActive(field, opt.value)\"\n (Clicked)=\"onChipClick(field, opt.value)\">\n </mj-filter-chip>\n }\n </div>\n }\n }\n </mj-filter-field>\n }\n\n <!-- Escape hatch for custom field widgets (e.g. mj-tree-dropdown, date pickers) -->\n <ng-content></ng-content>\n </div>\n\n @if (ShowReset) {\n <div class=\"mj-filter-panel-footer\">\n <button type=\"button\" class=\"mj-filter-panel-reset\" (click)=\"Reset.emit()\">\n <i class=\"fa-solid fa-rotate-left\"></i> {{ ResetLabel }}\n </button>\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n }\n\n .mj-filter-panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-body {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-text-input {\n width: 100%;\n padding: 7px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font: inherit;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n }\n\n .mj-filter-panel-text-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n\n .mj-filter-panel-text-input::placeholder {\n color: var(--mj-text-muted);\n }\n\n .mj-filter-panel-chip-group {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n\n .mj-filter-panel-footer {\n display: flex;\n justify-content: flex-end;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n\n .mj-filter-panel-reset {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font: inherit;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n }\n\n .mj-filter-panel-reset:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n }\n\n .mj-filter-panel-reset i {\n font-size: 11px;\n }\n `]\n})\nexport class MJFilterPanelComponent {\n @Input() Fields: FilterFieldConfig[] = [];\n @Input() Values: Record<string, unknown> = {};\n @Input() ShowReset: boolean = true;\n @Input() ResetLabel: string = 'Reset filters';\n\n @Output() ValuesChange = new EventEmitter<Record<string, unknown>>();\n @Output() Reset = new EventEmitter<void>();\n\n public getValue(key: string): unknown {\n return this.Values?.[key];\n }\n\n public setValue(key: string, value: unknown): void {\n this.Values = { ...this.Values, [key]: value };\n this.ValuesChange.emit(this.Values);\n }\n\n /** Whether a chip option is currently active (handles single + multi). */\n public isChipActive(field: FilterFieldConfig, optValue: FilterOptionValue): boolean {\n if (field.multi) {\n const current = this.getValue(field.key);\n return Array.isArray(current) && current.includes(optValue);\n }\n return this.getValue(field.key) === optValue;\n }\n\n /** Chip click: replace (single-select) or toggle in/out of the array (multi). */\n public onChipClick(field: FilterFieldConfig, optValue: FilterOptionValue): void {\n if (!field.multi) {\n this.setValue(field.key, optValue);\n return;\n }\n const current = this.getValue(field.key);\n const next: FilterOptionValue[] = Array.isArray(current) ? [...current] : [];\n const idx = next.indexOf(optValue);\n if (idx >= 0) {\n next.splice(idx, 1);\n } else {\n next.push(optValue);\n }\n this.setValue(field.key, next);\n }\n}\n"]}
1
+ {"version":3,"file":"filter-panel.component.js","sourceRoot":"","sources":["../../../src/lib/filter-panel/filter-panel.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { MJDropdownComponent } from '../dropdown/dropdown.component';\nimport { MJFilterChipComponent } from '../filter-chip/filter-chip.component';\nimport { MJFilterFieldComponent } from '../filter-field/filter-field.component';\n\n/** Field types supported natively by <mj-filter-panel>. */\nexport type FilterFieldType = 'text' | 'dropdown' | 'chips';\n\n/** Per-field config understood by <mj-filter-panel>. */\nexport interface FilterFieldConfig {\n /** State key in the Values record. */\n key: string;\n /** Field type — drives which widget is rendered. */\n type: FilterFieldType;\n /** Display label. */\n label: string;\n /** Optional Font Awesome icon class (e.g. 'fa-solid fa-folder'). */\n icon?: string;\n /** Placeholder for text inputs / dropdowns. */\n placeholder?: string;\n /** Dropdown options (when type === 'dropdown'). Each option needs text + value. */\n options?: { text: string; value: string | number | boolean | null }[];\n /** Whether the dropdown should show an internal search box. */\n filterable?: boolean;\n /** Chip-group options (when type === 'chips'). */\n chipOptions?: { text: string; value: string | number | boolean | null; icon?: string }[];\n /**\n * For `type === 'chips'` only. When `true`, the chip group is multi-select:\n * the field's value is an **array** of selected option values and clicking a\n * chip toggles it in/out. When absent/false (default), the group is\n * single-select (value is the chosen option value, click replaces).\n */\n multi?: boolean;\n}\n\n/** Option value type shared by dropdown + chip options. */\ntype FilterOptionValue = string | number | boolean | null;\n\n/**\n * mj-filter-panel — Single centralized filter panel for all dashboards.\n *\n * Config-driven: pass an array of `FilterFieldConfig` plus a `Values` record;\n * the panel renders each field using the appropriate widget (text input,\n * `<mj-dropdown>`, or chip group), keeps everything visually consistent, and\n * emits state changes via `(ValuesChange)`.\n *\n * For widgets not covered by the config schema (tree-dropdown, date pickers,\n * etc.), project `<mj-filter-field>` elements as content — they render below\n * the config-driven fields with identical chrome.\n *\n * Example:\n * ```html\n * <mj-filter-panel\n * [Fields]=\"filterFields\"\n * [(Values)]=\"filterValues\"\n * (Reset)=\"onReset()\">\n *\n * <!-- escape hatch for custom widgets -->\n * <mj-filter-field Label=\"Category\" Icon=\"fa-solid fa-folder\">\n * <mj-tree-dropdown ...></mj-tree-dropdown>\n * </mj-filter-field>\n * </mj-filter-panel>\n * ```\n */\n@Component({\n selector: 'mj-filter-panel',\n standalone: true,\n imports: [CommonModule, FormsModule, MJDropdownComponent, MJFilterChipComponent, MJFilterFieldComponent],\n template: `\n <div class=\"mj-filter-panel\">\n <div class=\"mj-filter-panel-body\">\n @for (field of Fields; track field.key) {\n <mj-filter-field [Label]=\"field.label\" [Icon]=\"field.icon ?? null\">\n @switch (field.type) {\n @case ('text') {\n <input\n type=\"text\"\n class=\"mj-filter-panel-text-input\"\n [value]=\"getValue(field.key) ?? ''\"\n [placeholder]=\"field.placeholder ?? ''\"\n (input)=\"setValue(field.key, $any($event.target).value)\" />\n }\n @case ('dropdown') {\n <mj-dropdown\n [Data]=\"field.options ?? []\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n [Filterable]=\"!!field.filterable\"\n [Placeholder]=\"field.placeholder ?? ''\"\n [ngModel]=\"getValue(field.key)\"\n (ngModelChange)=\"setValue(field.key, $event)\">\n </mj-dropdown>\n }\n @case ('chips') {\n <div class=\"mj-filter-panel-chip-group\">\n @for (opt of field.chipOptions ?? []; track opt.value) {\n <mj-filter-chip\n [Label]=\"opt.text\"\n [Icon]=\"opt.icon ?? null\"\n [Active]=\"isChipActive(field, opt.value)\"\n (Clicked)=\"onChipClick(field, opt.value)\">\n </mj-filter-chip>\n }\n </div>\n }\n }\n </mj-filter-field>\n }\n\n <!-- Escape hatch for custom field widgets (e.g. mj-tree-dropdown, date pickers) -->\n <ng-content></ng-content>\n </div>\n\n @if (ShowReset) {\n <div class=\"mj-filter-panel-footer\">\n <button type=\"button\" class=\"mj-filter-panel-reset\" (click)=\"Reset.emit()\">\n <i class=\"fa-solid fa-rotate-left\"></i> {{ ResetLabel }}\n </button>\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n }\n\n .mj-filter-panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-body {\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .mj-filter-panel-text-input {\n width: 100%;\n padding: 7px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font: inherit;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n }\n\n .mj-filter-panel-text-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n\n .mj-filter-panel-text-input::placeholder {\n color: var(--mj-text-muted);\n }\n\n .mj-filter-panel-chip-group {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n\n .mj-filter-panel-footer {\n display: flex;\n justify-content: flex-end;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n\n .mj-filter-panel-reset {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font: inherit;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n }\n\n .mj-filter-panel-reset:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n }\n\n .mj-filter-panel-reset i {\n font-size: 11px;\n }\n `]\n})\nexport class MJFilterPanelComponent {\n @Input() Fields: FilterFieldConfig[] = [];\n @Input() Values: Record<string, unknown> = {};\n @Input() ShowReset: boolean = true;\n @Input() ResetLabel: string = 'Reset filters';\n\n @Output() ValuesChange = new EventEmitter<Record<string, unknown>>();\n @Output() Reset = new EventEmitter<void>();\n\n public GetValue(key: string): unknown {\n return this.Values?.[key];\n }\n\n /** @deprecated Use {@link GetValue}. */\n public getValue(key: string): unknown {\n return this.GetValue(key);\n }\n\n public SetValue(key: string, value: unknown): void {\n this.Values = { ...this.Values, [key]: value };\n this.ValuesChange.emit(this.Values);\n }\n\n /** @deprecated Use {@link SetValue}. */\n public setValue(key: string, value: unknown): void {\n return this.SetValue(key, value);\n }\n\n /** Whether a chip option is currently active (handles single + multi). */\n public IsChipActive(field: FilterFieldConfig, optValue: FilterOptionValue): boolean {\n if (field.multi) {\n const current = this.GetValue(field.key);\n return Array.isArray(current) && current.includes(optValue);\n }\n return this.GetValue(field.key) === optValue;\n }\n\n /** @deprecated Use {@link IsChipActive}. */\n public isChipActive(field: FilterFieldConfig, optValue: FilterOptionValue): boolean {\n return this.IsChipActive(field, optValue);\n }\n\n /** Chip click: replace (single-select) or toggle in/out of the array (multi). */\n public OnChipClick(field: FilterFieldConfig, optValue: FilterOptionValue): void {\n if (!field.multi) {\n this.SetValue(field.key, optValue);\n return;\n }\n const current = this.GetValue(field.key);\n const next: FilterOptionValue[] = Array.isArray(current) ? [...current] : [];\n const idx = next.indexOf(optValue);\n if (idx >= 0) {\n next.splice(idx, 1);\n } else {\n next.push(optValue);\n }\n this.SetValue(field.key, next);\n }\n\n /** @deprecated Use {@link OnChipClick}. */\n public onChipClick(field: FilterFieldConfig, optValue: FilterOptionValue): void {\n return this.OnChipClick(field, optValue);\n }\n}\n"]}
@@ -1,9 +1,21 @@
1
+ import { AfterViewInit } from '@angular/core';
1
2
  import { ControlValueAccessor } from '@angular/forms';
3
+ import { MJNamedControlBase } from '../a11y/named-control.base';
2
4
  import * as i0 from "@angular/core";
3
5
  /**
4
6
  * mj-numeric-input — Numeric input with min/max/step. Replaces `<kendo-numerictextbox>`.
7
+ *
8
+ * A spinbutton with no accessible name announces as "spin button, blank" (WCAG 2.1 4.1.2). Use
9
+ * {@link MJNamedControlBase.AriaLabelledBy} when a visible label exists,
10
+ * {@link MJNamedControlBase.AriaLabel} when none does. The control here is a real `<input>`, so
11
+ * {@link MJNamedControlBase.InputId} IS a valid `<label for>` target.
12
+ *
13
+ * @example
14
+ * ```html
15
+ * <mj-numeric-input AriaLabel="Quantity" [(ngModel)]="quantity" [Min]="0" [Max]="100" />
16
+ * ```
5
17
  */
6
- export declare class MJNumericInputComponent implements ControlValueAccessor {
18
+ export declare class MJNumericInputComponent extends MJNamedControlBase implements ControlValueAccessor, AfterViewInit {
7
19
  Min: number | null;
8
20
  Max: number | null;
9
21
  Step: number;
@@ -19,6 +31,7 @@ export declare class MJNumericInputComponent implements ControlValueAccessor {
19
31
  get Disabled(): boolean;
20
32
  Placeholder: string;
21
33
  readonly hostClass = true;
34
+ private numericInputEl;
22
35
  /** The rendered `[disabled]` state — true when EITHER source says so. Assign via `syncDisabled()`. */
23
36
  IsDisabled: boolean;
24
37
  private disabledInput;
@@ -38,6 +51,7 @@ export declare class MJNumericInputComponent implements ControlValueAccessor {
38
51
  private internalValue;
39
52
  private onChange;
40
53
  private onTouched;
54
+ ngAfterViewInit(): void;
41
55
  OnInput(event: Event): void;
42
56
  OnBlur(): void;
43
57
  writeValue(value: number | null): void;
@@ -1 +1 @@
1
- {"version":3,"file":"numeric-input.component.d.ts","sourceRoot":"","sources":["../../../src/lib/numeric-input/numeric-input.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;;AAEzE;;GAEG;AACH,qBAYa,uBAAwB,YAAW,oBAAoB;IACzD,GAAG,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC1B,IAAI,EAAE,MAAM,CAAK;IACjB,MAAM,EAAE,MAAM,CAAM;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IACxC;;;;;OAKG;IACH,IACI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAsD;IACjF,IAAI,QAAQ,IAAI,OAAO,CAA+B;IAC7C,WAAW,SAAM;IACkB,QAAQ,CAAC,SAAS,QAAQ;IAEtE,sGAAsG;IACtG,UAAU,UAAS;IACnB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,GAAG,CAA6B;IAExC;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IAOpB,YAAY,EAAE,MAAM,GAAG,MAAM,CAAM;IACnC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,SAAS,CAAwB;IAEzC,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAU3B,MAAM,IAAI,IAAI;IAEd,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IACtC,gBAAgB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI;IAC1D,iBAAiB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IACvC,gBAAgB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI;IAE3C,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,aAAa;yCArEV,uBAAuB;2CAAvB,uBAAuB;CAyEnC"}
1
+ {"version":3,"file":"numeric-input.component.d.ts","sourceRoot":"","sources":["../../../src/lib/numeric-input/numeric-input.component.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EASd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAqB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;;AAGhE;;;;;;;;;;;;GAYG;AACH,qBAgBa,uBAAwB,SAAQ,kBAAmB,YAAW,oBAAoB,EAAE,aAAa;IACnG,GAAG,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC1B,IAAI,EAAE,MAAM,CAAK;IACjB,MAAM,EAAE,MAAM,CAAM;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IACxC;;;;;OAKG;IACH,IACI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAsD;IACjF,IAAI,QAAQ,IAAI,OAAO,CAA+B;IAC7C,WAAW,SAAM;IACkB,QAAQ,CAAC,SAAS,QAAQ;IAC3C,OAAO,CAAC,cAAc,CAA2C;IAE5F,sGAAsG;IACtG,UAAU,UAAS;IACnB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,GAAG,CAA6B;IAExC;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IAOpB,YAAY,EAAE,MAAM,GAAG,MAAM,CAAM;IACnC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,SAAS,CAAwB;IAEzC,eAAe,IAAI,IAAI;IAEvB,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAU3B,MAAM,IAAI,IAAI;IAEd,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IACtC,gBAAgB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI;IAC1D,iBAAiB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IACvC,gBAAgB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI;IAE3C,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,aAAa;yCAxEV,uBAAuB;2CAAvB,uBAAuB;CA4EnC"}
@@ -1,10 +1,23 @@
1
- import { Component, Input, forwardRef, HostBinding, ChangeDetectorRef, inject } from '@angular/core';
1
+ import { ChangeDetectorRef, Component, HostBinding, Input, ViewChild, forwardRef, inject } from '@angular/core';
2
2
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
3
+ import { MJNamedControlBase } from '../a11y/named-control.base';
4
+ import { WarnIfUnnamed } from '../a11y/unnamed-control-guard';
3
5
  import * as i0 from "@angular/core";
6
+ const _c0 = ["numericInput"];
4
7
  /**
5
8
  * mj-numeric-input — Numeric input with min/max/step. Replaces `<kendo-numerictextbox>`.
9
+ *
10
+ * A spinbutton with no accessible name announces as "spin button, blank" (WCAG 2.1 4.1.2). Use
11
+ * {@link MJNamedControlBase.AriaLabelledBy} when a visible label exists,
12
+ * {@link MJNamedControlBase.AriaLabel} when none does. The control here is a real `<input>`, so
13
+ * {@link MJNamedControlBase.InputId} IS a valid `<label for>` target.
14
+ *
15
+ * @example
16
+ * ```html
17
+ * <mj-numeric-input AriaLabel="Quantity" [(ngModel)]="quantity" [Min]="0" [Max]="100" />
18
+ * ```
6
19
  */
7
- export class MJNumericInputComponent {
20
+ export class MJNumericInputComponent extends MJNamedControlBase {
8
21
  Min = null;
9
22
  Max = null;
10
23
  Step = 1;
@@ -20,6 +33,7 @@ export class MJNumericInputComponent {
20
33
  get Disabled() { return this.disabledInput; }
21
34
  Placeholder = '';
22
35
  hostClass = true;
36
+ numericInputEl;
23
37
  /** The rendered `[disabled]` state — true when EITHER source says so. Assign via `syncDisabled()`. */
24
38
  IsDisabled = false;
25
39
  disabledInput = false;
@@ -45,6 +59,7 @@ export class MJNumericInputComponent {
45
59
  internalValue = null;
46
60
  onChange = () => { };
47
61
  onTouched = () => { };
62
+ ngAfterViewInit() { WarnIfUnnamed(this.numericInputEl?.nativeElement, 'mj-numeric-input'); }
48
63
  OnInput(event) {
49
64
  const raw = event.target.value;
50
65
  if (raw === '' || raw === '-') {
@@ -82,16 +97,21 @@ export class MJNumericInputComponent {
82
97
  }
83
98
  this.DisplayValue = this.Decimals != null ? this.internalValue.toFixed(this.Decimals) : this.internalValue;
84
99
  }
85
- static ɵfac = function MJNumericInputComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJNumericInputComponent)(); };
86
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJNumericInputComponent, selectors: [["mj-numeric-input"]], hostVars: 2, hostBindings: function MJNumericInputComponent_HostBindings(rf, ctx) { if (rf & 2) {
100
+ static ɵfac = /*@__PURE__*/ (() => { let ɵMJNumericInputComponent_BaseFactory; return function MJNumericInputComponent_Factory(__ngFactoryType__) { return (ɵMJNumericInputComponent_BaseFactory || (ɵMJNumericInputComponent_BaseFactory = i0.ɵɵgetInheritedFactory(MJNumericInputComponent)))(__ngFactoryType__ || MJNumericInputComponent); }; })();
101
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJNumericInputComponent, selectors: [["mj-numeric-input"]], viewQuery: function MJNumericInputComponent_Query(rf, ctx) { if (rf & 1) {
102
+ i0.ɵɵviewQuery(_c0, 5);
103
+ } if (rf & 2) {
104
+ let _t;
105
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.numericInputEl = _t.first);
106
+ } }, hostVars: 2, hostBindings: function MJNumericInputComponent_HostBindings(rf, ctx) { if (rf & 2) {
87
107
  i0.ɵɵclassProp("mj-numeric-input-host", ctx.hostClass);
88
- } }, inputs: { Min: "Min", Max: "Max", Step: "Step", Format: "Format", Decimals: "Decimals", Disabled: "Disabled", Placeholder: "Placeholder" }, features: [i0.ɵɵProvidersFeature([{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MJNumericInputComponent), multi: true }])], decls: 1, vars: 6, consts: [["type", "number", 1, "mj-input", "mj-numeric-input", 3, "input", "blur", "disabled", "value"]], template: function MJNumericInputComponent_Template(rf, ctx) { if (rf & 1) {
89
- i0.ɵɵdomElementStart(0, "input", 0);
108
+ } }, inputs: { Min: "Min", Max: "Max", Step: "Step", Format: "Format", Decimals: "Decimals", Disabled: "Disabled", Placeholder: "Placeholder" }, features: [i0.ɵɵProvidersFeature([{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MJNumericInputComponent), multi: true }]), i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 10, consts: [["numericInput", ""], ["type", "number", 1, "mj-input", "mj-numeric-input", 3, "input", "blur", "disabled", "value"]], template: function MJNumericInputComponent_Template(rf, ctx) { if (rf & 1) {
109
+ i0.ɵɵdomElementStart(0, "input", 1, 0);
90
110
  i0.ɵɵdomListener("input", function MJNumericInputComponent_Template_input_input_0_listener($event) { return ctx.OnInput($event); })("blur", function MJNumericInputComponent_Template_input_blur_0_listener() { return ctx.OnBlur(); });
91
111
  i0.ɵɵdomElementEnd();
92
112
  } if (rf & 2) {
93
113
  i0.ɵɵdomProperty("disabled", ctx.IsDisabled)("value", ctx.DisplayValue);
94
- i0.ɵɵattribute("min", ctx.Min)("max", ctx.Max)("step", ctx.Step)("placeholder", ctx.Placeholder);
114
+ i0.ɵɵattribute("min", ctx.Min)("max", ctx.Max)("step", ctx.Step)("id", ctx.InputId || null)("aria-label", ctx.AriaLabel || null)("aria-labelledby", ctx.AriaLabelledBy || null)("aria-describedby", ctx.AriaDescribedBy || null)("placeholder", ctx.Placeholder);
95
115
  } }, encapsulation: 2 });
96
116
  }
97
117
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJNumericInputComponent, [{
@@ -100,8 +120,12 @@ export class MJNumericInputComponent {
100
120
  selector: 'mj-numeric-input',
101
121
  standalone: true,
102
122
  template: `
103
- <input type="number" class="mj-input mj-numeric-input"
123
+ <input #numericInput type="number" class="mj-input mj-numeric-input"
104
124
  [attr.min]="Min" [attr.max]="Max" [attr.step]="Step"
125
+ [attr.id]="InputId || null"
126
+ [attr.aria-label]="AriaLabel || null"
127
+ [attr.aria-labelledby]="AriaLabelledBy || null"
128
+ [attr.aria-describedby]="AriaDescribedBy || null"
105
129
  [attr.placeholder]="Placeholder" [disabled]="IsDisabled"
106
130
  [value]="DisplayValue"
107
131
  (input)="OnInput($event)" (blur)="OnBlur()" />
@@ -125,6 +149,9 @@ export class MJNumericInputComponent {
125
149
  }], hostClass: [{
126
150
  type: HostBinding,
127
151
  args: ['class.mj-numeric-input-host']
152
+ }], numericInputEl: [{
153
+ type: ViewChild,
154
+ args: ['numericInput']
128
155
  }] }); })();
129
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJNumericInputComponent, { className: "MJNumericInputComponent", filePath: "lib/numeric-input/numeric-input.component.ts", lineNumber: 19 }); })();
156
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJNumericInputComponent, { className: "MJNumericInputComponent", filePath: "lib/numeric-input/numeric-input.component.ts", lineNumber: 45 }); })();
130
157
  //# sourceMappingURL=numeric-input.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"numeric-input.component.js","sourceRoot":"","sources":["../../../src/lib/numeric-input/numeric-input.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, forwardRef, HostBinding, ChangeDetectorRef, inject } from '@angular/core';\nimport { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';\n\n/**\n * mj-numeric-input — Numeric input with min/max/step. Replaces `<kendo-numerictextbox>`.\n */\n@Component({\n selector: 'mj-numeric-input',\n standalone: true,\n template: `\n <input type=\"number\" class=\"mj-input mj-numeric-input\"\n [attr.min]=\"Min\" [attr.max]=\"Max\" [attr.step]=\"Step\"\n [attr.placeholder]=\"Placeholder\" [disabled]=\"IsDisabled\"\n [value]=\"DisplayValue\"\n (input)=\"OnInput($event)\" (blur)=\"OnBlur()\" />\n `,\n providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MJNumericInputComponent), multi: true }]\n})\nexport class MJNumericInputComponent implements ControlValueAccessor {\n @Input() Min: number | null = null;\n @Input() Max: number | null = null;\n @Input() Step: number = 1;\n @Input() Format: string = '';\n @Input() Decimals: number | null = null;\n /**\n * Host-driven disable. Composed with Angular Forms' `setDisabledState()` into `IsDisabled`\n * (the actual gate) — see `syncDisabled`. A setter, not a bare field, because this input is\n * routinely bound to an expression that changes over the control's lifetime, and the gate has\n * to follow it every time.\n */\n @Input()\n set Disabled(value: boolean) { this.disabledInput = value; this.syncDisabled(); }\n get Disabled(): boolean { return this.disabledInput; }\n @Input() Placeholder = '';\n @HostBinding('class.mj-numeric-input-host') readonly hostClass = true;\n\n /** The rendered `[disabled]` state — true when EITHER source says so. Assign via `syncDisabled()`. */\n IsDisabled = false;\n private disabledInput = false;\n private formDisabled = false;\n private cdr = inject(ChangeDetectorRef);\n\n /**\n * Recompute the gate from both of its sources. Called whenever either one changes.\n *\n * `IsDisabled` is derived state, and the only thing that assigned it was `setDisabledState()`.\n * The forms-driven half was in fact fine — `setUpControl` also wires `registerOnDisabledChange`,\n * so that hook fires on every `control.disable()`/`enable()`, not just at registration. What had\n * no recompute path at all was the `Disabled` @Input: a plain field, so the gate froze at\n * whatever the first compose produced and every later change to the input was dropped.\n */\n private syncDisabled(): void {\n const disabled = this.disabledInput || this.formDisabled;\n if (disabled === this.IsDisabled) return;\n this.IsDisabled = disabled;\n this.cdr.markForCheck();\n }\n\n DisplayValue: string | number = '';\n private internalValue: number | null = null;\n private onChange: (value: number | null) => void = () => {};\n private onTouched: () => void = () => {};\n\n OnInput(event: Event): void {\n const raw = (event.target as HTMLInputElement).value;\n if (raw === '' || raw === '-') { this.internalValue = null; this.onChange(null); return; }\n let num = parseFloat(raw);\n if (isNaN(num)) return;\n num = this.clamp(num);\n this.internalValue = num;\n this.onChange(num);\n }\n\n OnBlur(): void { this.onTouched(); this.formatDisplay(); }\n\n writeValue(value: number | null): void { this.internalValue = value; this.formatDisplay(); }\n registerOnChange(fn: (value: number | null) => void): void { this.onChange = fn; }\n registerOnTouched(fn: () => void): void { this.onTouched = fn; }\n setDisabledState(isDisabled: boolean): void { this.formDisabled = isDisabled; this.syncDisabled(); }\n\n private clamp(value: number): number {\n if (this.Min != null && value < this.Min) return this.Min;\n if (this.Max != null && value > this.Max) return this.Max;\n if (this.Decimals != null) { const f = Math.pow(10, this.Decimals); return Math.round(value * f) / f; }\n return value;\n }\n\n private formatDisplay(): void {\n if (this.internalValue == null) { this.DisplayValue = ''; return; }\n this.DisplayValue = this.Decimals != null ? this.internalValue.toFixed(this.Decimals) : this.internalValue;\n }\n}\n"]}
1
+ {"version":3,"file":"numeric-input.component.js","sourceRoot":"","sources":["../../../src/lib/numeric-input/numeric-input.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AfterViewInit,\n ChangeDetectorRef,\n Component,\n ElementRef,\n HostBinding,\n Input,\n ViewChild,\n forwardRef,\n inject\n} from '@angular/core';\nimport { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';\nimport { MJNamedControlBase } from '../a11y/named-control.base';\nimport { WarnIfUnnamed } from '../a11y/unnamed-control-guard';\n\n/**\n * mj-numeric-input — Numeric input with min/max/step. Replaces `<kendo-numerictextbox>`.\n *\n * A spinbutton with no accessible name announces as \"spin button, blank\" (WCAG 2.1 4.1.2). Use\n * {@link MJNamedControlBase.AriaLabelledBy} when a visible label exists,\n * {@link MJNamedControlBase.AriaLabel} when none does. The control here is a real `<input>`, so\n * {@link MJNamedControlBase.InputId} IS a valid `<label for>` target.\n *\n * @example\n * ```html\n * <mj-numeric-input AriaLabel=\"Quantity\" [(ngModel)]=\"quantity\" [Min]=\"0\" [Max]=\"100\" />\n * ```\n */\n@Component({\n selector: 'mj-numeric-input',\n standalone: true,\n template: `\n <input #numericInput type=\"number\" class=\"mj-input mj-numeric-input\"\n [attr.min]=\"Min\" [attr.max]=\"Max\" [attr.step]=\"Step\"\n [attr.id]=\"InputId || null\"\n [attr.aria-label]=\"AriaLabel || null\"\n [attr.aria-labelledby]=\"AriaLabelledBy || null\"\n [attr.aria-describedby]=\"AriaDescribedBy || null\"\n [attr.placeholder]=\"Placeholder\" [disabled]=\"IsDisabled\"\n [value]=\"DisplayValue\"\n (input)=\"OnInput($event)\" (blur)=\"OnBlur()\" />\n `,\n providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MJNumericInputComponent), multi: true }]\n})\nexport class MJNumericInputComponent extends MJNamedControlBase implements ControlValueAccessor, AfterViewInit {\n @Input() Min: number | null = null;\n @Input() Max: number | null = null;\n @Input() Step: number = 1;\n @Input() Format: string = '';\n @Input() Decimals: number | null = null;\n /**\n * Host-driven disable. Composed with Angular Forms' `setDisabledState()` into `IsDisabled`\n * (the actual gate) — see `syncDisabled`. A setter, not a bare field, because this input is\n * routinely bound to an expression that changes over the control's lifetime, and the gate has\n * to follow it every time.\n */\n @Input()\n set Disabled(value: boolean) { this.disabledInput = value; this.syncDisabled(); }\n get Disabled(): boolean { return this.disabledInput; }\n @Input() Placeholder = '';\n @HostBinding('class.mj-numeric-input-host') readonly hostClass = true;\n @ViewChild('numericInput') private numericInputEl: ElementRef<HTMLInputElement> | undefined;\n\n /** The rendered `[disabled]` state — true when EITHER source says so. Assign via `syncDisabled()`. */\n IsDisabled = false;\n private disabledInput = false;\n private formDisabled = false;\n private cdr = inject(ChangeDetectorRef);\n\n /**\n * Recompute the gate from both of its sources. Called whenever either one changes.\n *\n * `IsDisabled` is derived state, and the only thing that assigned it was `setDisabledState()`.\n * The forms-driven half was in fact fine — `setUpControl` also wires `registerOnDisabledChange`,\n * so that hook fires on every `control.disable()`/`enable()`, not just at registration. What had\n * no recompute path at all was the `Disabled` @Input: a plain field, so the gate froze at\n * whatever the first compose produced and every later change to the input was dropped.\n */\n private syncDisabled(): void {\n const disabled = this.disabledInput || this.formDisabled;\n if (disabled === this.IsDisabled) return;\n this.IsDisabled = disabled;\n this.cdr.markForCheck();\n }\n\n DisplayValue: string | number = '';\n private internalValue: number | null = null;\n private onChange: (value: number | null) => void = () => {};\n private onTouched: () => void = () => {};\n\n ngAfterViewInit(): void { WarnIfUnnamed(this.numericInputEl?.nativeElement, 'mj-numeric-input'); }\n\n OnInput(event: Event): void {\n const raw = (event.target as HTMLInputElement).value;\n if (raw === '' || raw === '-') { this.internalValue = null; this.onChange(null); return; }\n let num = parseFloat(raw);\n if (isNaN(num)) return;\n num = this.clamp(num);\n this.internalValue = num;\n this.onChange(num);\n }\n\n OnBlur(): void { this.onTouched(); this.formatDisplay(); }\n\n writeValue(value: number | null): void { this.internalValue = value; this.formatDisplay(); }\n registerOnChange(fn: (value: number | null) => void): void { this.onChange = fn; }\n registerOnTouched(fn: () => void): void { this.onTouched = fn; }\n setDisabledState(isDisabled: boolean): void { this.formDisabled = isDisabled; this.syncDisabled(); }\n\n private clamp(value: number): number {\n if (this.Min != null && value < this.Min) return this.Min;\n if (this.Max != null && value > this.Max) return this.Max;\n if (this.Decimals != null) { const f = Math.pow(10, this.Decimals); return Math.round(value * f) / f; }\n return value;\n }\n\n private formatDisplay(): void {\n if (this.internalValue == null) { this.DisplayValue = ''; return; }\n this.DisplayValue = this.Decimals != null ? this.internalValue.toFixed(this.Decimals) : this.internalValue;\n }\n}\n"]}
@@ -1,4 +1,5 @@
1
- import { EventEmitter } from '@angular/core';
1
+ import { AfterViewInit, EventEmitter } from '@angular/core';
2
+ import { MJNamedControlBase } from '../a11y/named-control.base';
2
3
  import * as i0 from "@angular/core";
3
4
  /**
4
5
  * mj-page-search — Canonical in-page search input for dashboard headers and toolbars.
@@ -7,21 +8,49 @@ import * as i0 from "@angular/core";
7
8
  * Distinct from `mj-search-input` (the navbar/global search in `@memberjunction/ng-search`)
8
9
  * — this one is a simple text input used for filtering page content.
9
10
  *
11
+ * The `Placeholder` is the accessible name of last resort — it is what the name computation falls
12
+ * back to, and it disappears the moment the user types. Pass
13
+ * {@link MJNamedControlBase.AriaLabel} (or {@link MJNamedControlBase.AriaLabelledBy} when a visible
14
+ * label exists) so the box has a name that survives having text in it. The control is a real
15
+ * `<input>`, so {@link MJNamedControlBase.InputId} IS a valid `<label for>` target.
16
+ *
10
17
  * Example:
11
18
  * ```html
12
19
  * <mj-page-search
20
+ * AriaLabel="Search templates"
13
21
  * Placeholder="Search templates..."
14
22
  * [Value]="searchTerm"
15
23
  * (ValueChange)="onSearch($event)">
16
24
  * </mj-page-search>
17
25
  * ```
18
26
  */
19
- export declare class MJPageSearchComponent {
27
+ export declare class MJPageSearchComponent extends MJNamedControlBase implements AfterViewInit {
28
+ /** The placeholder a caller gets by having said nothing — it names no particular search. */
29
+ static readonly GenericPlaceholder = "Search...";
20
30
  Placeholder: string;
21
31
  Value: string;
22
32
  Icon: string;
23
33
  ValueChange: EventEmitter<string>;
24
- focused: boolean;
34
+ private searchInputEl;
35
+ Focused: boolean;
36
+ /** @deprecated Use {@link Focused}. */
37
+ get focused(): boolean;
38
+ /** @deprecated Use {@link Focused}. */
39
+ set focused(value: boolean);
40
+ /**
41
+ * `PlaceholderIsName` is passed here and nowhere else: this is a toolbar widget whose placeholder
42
+ * ("Search templates…") IS the caller's statement of what the box searches. On a form control a
43
+ * placeholder is not a name — it disappears as soon as the user types — so those controls warn
44
+ * without one.
45
+ *
46
+ * It is not passed unconditionally, or the guard could never fire here at all: the default
47
+ * placeholder is non-empty, so accepting any placeholder would accept `'Search...'`, which tells a
48
+ * screen-reader user nothing about what is being searched. Only a placeholder the caller actually
49
+ * chose counts.
50
+ */
51
+ ngAfterViewInit(): void;
52
+ OnInput(event: Event): void;
53
+ /** @deprecated Use {@link OnInput}. */
25
54
  onInput(event: Event): void;
26
55
  static ɵfac: i0.ɵɵFactoryDeclaration<MJPageSearchComponent, never>;
27
56
  static ɵcmp: i0.ɵɵComponentDeclaration<MJPageSearchComponent, "mj-page-search", never, { "Placeholder": { "alias": "Placeholder"; "required": false; }; "Value": { "alias": "Value"; "required": false; }; "Icon": { "alias": "Icon"; "required": false; }; }, { "ValueChange": "ValueChange"; }, never, never, true, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"page-search.component.d.ts","sourceRoot":"","sources":["../../../src/lib/page-search/page-search.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;;AAEvE;;;;;;;;;;;;;;;GAeG;AACH,qBA0Ea,qBAAqB;IACvB,WAAW,EAAE,MAAM,CAAe;IAClC,KAAK,EAAE,MAAM,CAAM;IACnB,IAAI,EAAE,MAAM,CAAwB;IACnC,WAAW,uBAA8B;IAE5C,OAAO,EAAE,OAAO,CAAS;IAEzB,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;yCARvB,qBAAqB;2CAArB,qBAAqB;CAajC"}
1
+ {"version":3,"file":"page-search.component.d.ts","sourceRoot":"","sources":["../../../src/lib/page-search/page-search.component.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAGb,YAAY,EAIb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;;AAGhE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAgFa,qBAAsB,SAAQ,kBAAmB,YAAW,aAAa;IACpF,4FAA4F;IAC5F,MAAM,CAAC,QAAQ,CAAC,kBAAkB,eAAe;IAExC,WAAW,EAAE,MAAM,CAA4C;IAC/D,KAAK,EAAE,MAAM,CAAM;IACnB,IAAI,EAAE,MAAM,CAAwB;IACnC,WAAW,uBAA8B;IAEzB,OAAO,CAAC,aAAa,CAA2C;IAEnF,OAAO,EAAE,OAAO,CAAS;IAEhC,uCAAuC;IACvC,IAAW,OAAO,IAAI,OAAO,CAE5B;IACD,uCAAuC;IACvC,IAAW,OAAO,CAAC,KAAK,EAAE,OAAO,EAEhC;IAED;;;;;;;;;;OAUG;IACI,eAAe,IAAI,IAAI;IAMvB,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMlC,uCAAuC;IAChC,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;yCA9CvB,qBAAqB;2CAArB,qBAAqB;CAiDjC"}
@@ -1,5 +1,8 @@
1
- import { Component, EventEmitter, Input, Output } from '@angular/core';
1
+ import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
2
+ import { MJNamedControlBase } from '../a11y/named-control.base';
3
+ import { WarnIfUnnamed } from '../a11y/unnamed-control-guard';
2
4
  import * as i0 from "@angular/core";
5
+ const _c0 = ["searchInput"];
3
6
  /**
4
7
  * mj-page-search — Canonical in-page search input for dashboard headers and toolbars.
5
8
  * Replaces per-page `.search-input-wrapper` rules so styling can't drift.
@@ -7,31 +10,74 @@ import * as i0 from "@angular/core";
7
10
  * Distinct from `mj-search-input` (the navbar/global search in `@memberjunction/ng-search`)
8
11
  * — this one is a simple text input used for filtering page content.
9
12
  *
13
+ * The `Placeholder` is the accessible name of last resort — it is what the name computation falls
14
+ * back to, and it disappears the moment the user types. Pass
15
+ * {@link MJNamedControlBase.AriaLabel} (or {@link MJNamedControlBase.AriaLabelledBy} when a visible
16
+ * label exists) so the box has a name that survives having text in it. The control is a real
17
+ * `<input>`, so {@link MJNamedControlBase.InputId} IS a valid `<label for>` target.
18
+ *
10
19
  * Example:
11
20
  * ```html
12
21
  * <mj-page-search
22
+ * AriaLabel="Search templates"
13
23
  * Placeholder="Search templates..."
14
24
  * [Value]="searchTerm"
15
25
  * (ValueChange)="onSearch($event)">
16
26
  * </mj-page-search>
17
27
  * ```
18
28
  */
19
- export class MJPageSearchComponent {
20
- Placeholder = 'Search...';
29
+ export class MJPageSearchComponent extends MJNamedControlBase {
30
+ /** The placeholder a caller gets by having said nothing — it names no particular search. */
31
+ static GenericPlaceholder = 'Search...';
32
+ Placeholder = MJPageSearchComponent.GenericPlaceholder;
21
33
  Value = '';
22
34
  Icon = 'fa-solid fa-search';
23
35
  ValueChange = new EventEmitter();
24
- focused = false;
25
- onInput(event) {
36
+ searchInputEl;
37
+ Focused = false;
38
+ /** @deprecated Use {@link Focused}. */
39
+ get focused() {
40
+ return this.Focused;
41
+ }
42
+ /** @deprecated Use {@link Focused}. */
43
+ set focused(value) {
44
+ this.Focused = value;
45
+ }
46
+ /**
47
+ * `PlaceholderIsName` is passed here and nowhere else: this is a toolbar widget whose placeholder
48
+ * ("Search templates…") IS the caller's statement of what the box searches. On a form control a
49
+ * placeholder is not a name — it disappears as soon as the user types — so those controls warn
50
+ * without one.
51
+ *
52
+ * It is not passed unconditionally, or the guard could never fire here at all: the default
53
+ * placeholder is non-empty, so accepting any placeholder would accept `'Search...'`, which tells a
54
+ * screen-reader user nothing about what is being searched. Only a placeholder the caller actually
55
+ * chose counts.
56
+ */
57
+ ngAfterViewInit() {
58
+ WarnIfUnnamed(this.searchInputEl?.nativeElement, 'mj-page-search', {
59
+ PlaceholderIsName: this.Placeholder !== MJPageSearchComponent.GenericPlaceholder
60
+ });
61
+ }
62
+ OnInput(event) {
26
63
  const v = event.target.value;
27
64
  this.Value = v;
28
65
  this.ValueChange.emit(v);
29
66
  }
30
- static ɵfac = function MJPageSearchComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJPageSearchComponent)(); };
31
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJPageSearchComponent, selectors: [["mj-page-search"]], inputs: { Placeholder: "Placeholder", Value: "Value", Icon: "Icon" }, outputs: { ValueChange: "ValueChange" }, decls: 3, vars: 6, consts: [[1, "mj-page-search"], ["type", "text", 3, "input", "focus", "blur", "placeholder", "value"]], template: function MJPageSearchComponent_Template(rf, ctx) { if (rf & 1) {
32
- i0.ɵɵdomElementStart(0, "div", 0);
33
- i0.ɵɵdomElement(1, "i");
34
- i0.ɵɵdomElementStart(2, "input", 1);
67
+ /** @deprecated Use {@link OnInput}. */
68
+ onInput(event) {
69
+ return this.OnInput(event);
70
+ }
71
+ static ɵfac = /*@__PURE__*/ (() => { let ɵMJPageSearchComponent_BaseFactory; return function MJPageSearchComponent_Factory(__ngFactoryType__) { return (ɵMJPageSearchComponent_BaseFactory || (ɵMJPageSearchComponent_BaseFactory = i0.ɵɵgetInheritedFactory(MJPageSearchComponent)))(__ngFactoryType__ || MJPageSearchComponent); }; })();
72
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJPageSearchComponent, selectors: [["mj-page-search"]], viewQuery: function MJPageSearchComponent_Query(rf, ctx) { if (rf & 1) {
73
+ i0.ɵɵviewQuery(_c0, 5);
74
+ } if (rf & 2) {
75
+ let _t;
76
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.searchInputEl = _t.first);
77
+ } }, inputs: { Placeholder: "Placeholder", Value: "Value", Icon: "Icon" }, outputs: { ValueChange: "ValueChange" }, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 10, consts: [["searchInput", ""], [1, "mj-page-search"], ["aria-hidden", "true"], ["type", "text", 3, "input", "focus", "blur", "placeholder", "value"]], template: function MJPageSearchComponent_Template(rf, ctx) { if (rf & 1) {
78
+ i0.ɵɵdomElementStart(0, "div", 1);
79
+ i0.ɵɵdomElement(1, "i", 2);
80
+ i0.ɵɵdomElementStart(2, "input", 3, 0);
35
81
  i0.ɵɵdomListener("input", function MJPageSearchComponent_Template_input_input_2_listener($event) { return ctx.onInput($event); })("focus", function MJPageSearchComponent_Template_input_focus_2_listener() { return ctx.focused = true; })("blur", function MJPageSearchComponent_Template_input_blur_2_listener() { return ctx.focused = false; });
36
82
  i0.ɵɵdomElementEnd()();
37
83
  } if (rf & 2) {
@@ -40,15 +86,22 @@ export class MJPageSearchComponent {
40
86
  i0.ɵɵclassMap(ctx.Icon);
41
87
  i0.ɵɵadvance();
42
88
  i0.ɵɵdomProperty("placeholder", ctx.Placeholder)("value", ctx.Value);
89
+ i0.ɵɵattribute("id", ctx.InputId || null)("aria-label", ctx.AriaLabel || null)("aria-labelledby", ctx.AriaLabelledBy || null)("aria-describedby", ctx.AriaDescribedBy || null);
43
90
  } }, styles: ["[_nghost-%COMP%] {\n display: inline-flex;\n min-width: 220px;\n }\n\n \n\n\n\n\n .mj-page-search[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n width: 100%;\n padding: var(--mj-space-1) var(--mj-space-3);\n font-family: var(--mj-font-family);\n font-size: var(--mj-text-sm);\n line-height: 1.5;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n transition: var(--mj-transition-colors), box-shadow var(--mj-transition-base);\n min-height: 32px;\n box-sizing: border-box;\n }\n\n .mj-page-search[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n }\n\n .mj-page-search--focused[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-focus-ring);\n }\n\n .mj-page-search[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 13px;\n flex-shrink: 0;\n }\n\n .mj-page-search[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n font: inherit;\n color: var(--mj-text-primary);\n min-width: 0;\n }\n\n .mj-page-search[_ngcontent-%COMP%] input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-disabled);\n }"] });
44
91
  }
45
92
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJPageSearchComponent, [{
46
93
  type: Component,
47
94
  args: [{ selector: 'mj-page-search', standalone: true, template: `
48
95
  <div class="mj-page-search" [class.mj-page-search--focused]="focused">
49
- <i [class]="Icon"></i>
96
+ <!-- Decorative: the magnifier repeats what the name and placeholder already say. -->
97
+ <i [class]="Icon" aria-hidden="true"></i>
50
98
  <input
99
+ #searchInput
51
100
  type="text"
101
+ [attr.id]="InputId || null"
102
+ [attr.aria-label]="AriaLabel || null"
103
+ [attr.aria-labelledby]="AriaLabelledBy || null"
104
+ [attr.aria-describedby]="AriaDescribedBy || null"
52
105
  [placeholder]="Placeholder"
53
106
  [value]="Value"
54
107
  (input)="onInput($event)"
@@ -64,6 +117,9 @@ export class MJPageSearchComponent {
64
117
  type: Input
65
118
  }], ValueChange: [{
66
119
  type: Output
120
+ }], searchInputEl: [{
121
+ type: ViewChild,
122
+ args: ['searchInput']
67
123
  }] }); })();
68
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJPageSearchComponent, { className: "MJPageSearchComponent", filePath: "lib/page-search/page-search.component.ts", lineNumber: 93 }); })();
124
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJPageSearchComponent, { className: "MJPageSearchComponent", filePath: "lib/page-search/page-search.component.ts", lineNumber: 116 }); })();
69
125
  //# sourceMappingURL=page-search.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"page-search.component.js","sourceRoot":"","sources":["../../../src/lib/page-search/page-search.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;AAEvE;;;;;;;;;;;;;;;GAeG;AA2EH,MAAM,OAAO,qBAAqB;IACvB,WAAW,GAAW,WAAW,CAAC;IAClC,KAAK,GAAW,EAAE,CAAC;IACnB,IAAI,GAAW,oBAAoB,CAAC;IACnC,WAAW,GAAG,IAAI,YAAY,EAAU,CAAC;IAE5C,OAAO,GAAY,KAAK,CAAC;IAEzB,OAAO,CAAC,KAAY;QACzB,MAAM,CAAC,GAAI,KAAK,CAAC,MAA2B,CAAC,KAAK,CAAC;QACnD,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;+GAZU,qBAAqB;6DAArB,qBAAqB;YAtE9B,iCAAsE;YACpE,uBAAsB;YACtB,mCAM6B;YAA3B,AADA,AADA,0GAAS,mBAAe,IAAC,kGACN,IAAI,IAAC,gGACN,KAAK,IAAC;YAC5B,AAPE,oBAM6B,EACzB;;YATsB,sDAAyC;YAChE,cAAc;YAAd,uBAAc;YAGf,cAA2B;YAC3B,AADA,gDAA2B,oBACZ;;;iFAiEV,qBAAqB;cA1EjC,SAAS;2BACE,gBAAgB,cACd,IAAI,YACN;;;;;;;;;;;GAWT;;kBA6DA,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,MAAM;;kFAJI,qBAAqB","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\n\n/**\n * mj-page-search — Canonical in-page search input for dashboard headers and toolbars.\n * Replaces per-page `.search-input-wrapper` rules so styling can't drift.\n *\n * Distinct from `mj-search-input` (the navbar/global search in `@memberjunction/ng-search`)\n * — this one is a simple text input used for filtering page content.\n *\n * Example:\n * ```html\n * <mj-page-search\n * Placeholder=\"Search templates...\"\n * [Value]=\"searchTerm\"\n * (ValueChange)=\"onSearch($event)\">\n * </mj-page-search>\n * ```\n */\n@Component({\n selector: 'mj-page-search',\n standalone: true,\n template: `\n <div class=\"mj-page-search\" [class.mj-page-search--focused]=\"focused\">\n <i [class]=\"Icon\"></i>\n <input\n type=\"text\"\n [placeholder]=\"Placeholder\"\n [value]=\"Value\"\n (input)=\"onInput($event)\"\n (focus)=\"focused = true\"\n (blur)=\"focused = false\" />\n </div>\n `,\n styles: [`\n :host {\n display: inline-flex;\n min-width: 220px;\n }\n\n /* Compact toolbar density (32px) to match mjButton size=\"sm\" and other\n header widgets. White background + border-default for visual differentiation\n on both the page-header (white) and body (sunken) surfaces.\n Note: this is intentionally tighter than .mj-input (38px) because\n mj-page-search is a toolbar widget, not a form field. */\n .mj-page-search {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n width: 100%;\n padding: var(--mj-space-1) var(--mj-space-3);\n font-family: var(--mj-font-family);\n font-size: var(--mj-text-sm);\n line-height: 1.5;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n transition: var(--mj-transition-colors), box-shadow var(--mj-transition-base);\n min-height: 32px;\n box-sizing: border-box;\n }\n\n .mj-page-search:hover {\n border-color: var(--mj-border-strong);\n }\n\n .mj-page-search--focused {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-focus-ring);\n }\n\n .mj-page-search i {\n color: var(--mj-text-muted);\n font-size: 13px;\n flex-shrink: 0;\n }\n\n .mj-page-search input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n font: inherit;\n color: var(--mj-text-primary);\n min-width: 0;\n }\n\n .mj-page-search input::placeholder {\n color: var(--mj-text-disabled);\n }\n `]\n})\nexport class MJPageSearchComponent {\n @Input() Placeholder: string = 'Search...';\n @Input() Value: string = '';\n @Input() Icon: string = 'fa-solid fa-search';\n @Output() ValueChange = new EventEmitter<string>();\n\n public focused: boolean = false;\n\n public onInput(event: Event): void {\n const v = (event.target as HTMLInputElement).value;\n this.Value = v;\n this.ValueChange.emit(v);\n }\n}\n"]}
1
+ {"version":3,"file":"page-search.component.js","sourceRoot":"","sources":["../../../src/lib/page-search/page-search.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EAET,YAAY,EACZ,KAAK,EACL,MAAM,EACN,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;;;AAE9D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAiFH,MAAM,OAAO,qBAAsB,SAAQ,kBAAkB;IAC3D,4FAA4F;IAC5F,MAAM,CAAU,kBAAkB,GAAG,WAAW,CAAC;IAExC,WAAW,GAAW,qBAAqB,CAAC,kBAAkB,CAAC;IAC/D,KAAK,GAAW,EAAE,CAAC;IACnB,IAAI,GAAW,oBAAoB,CAAC;IACnC,WAAW,GAAG,IAAI,YAAY,EAAU,CAAC;IAEjB,aAAa,CAA2C;IAEnF,OAAO,GAAY,KAAK,CAAC;IAEhC,uCAAuC;IACvC,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,uCAAuC;IACvC,IAAW,OAAO,CAAC,KAAc;QAC/B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED;;;;;;;;;;OAUG;IACI,eAAe;QACpB,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE;YACjE,iBAAiB,EAAE,IAAI,CAAC,WAAW,KAAK,qBAAqB,CAAC,kBAAkB;SACjF,CAAC,CAAC;IACL,CAAC;IAEM,OAAO,CAAC,KAAY;QACzB,MAAM,CAAC,GAAI,KAAK,CAAC,MAA2B,CAAC,KAAK,CAAC;QACnD,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IAED,uCAAuC;IAChC,OAAO,CAAC,KAAY;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;iQAhDU,qBAAqB,yBAArB,qBAAqB;6DAArB,qBAAqB;;;;;;YA5E9B,iCAAsE;YAEpE,0BAAyC;YACzC,sCAW6B;YAA3B,AADA,AADA,0GAAS,mBAAe,IAAC,kGACN,IAAI,IAAC,gGACN,KAAK,IAAC;YAC5B,AAZE,oBAW6B,EACzB;;YAfsB,sDAAyC;YAEhE,cAAc;YAAd,uBAAc;YAQf,cAA2B;YAC3B,AADA,gDAA2B,oBACZ;;;;iFAiEV,qBAAqB;cAhFjC,SAAS;2BACE,gBAAgB,cACd,IAAI,YACN;;;;;;;;;;;;;;;;;GAiBT;;kBAgEA,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,MAAM;;kBAEN,SAAS;mBAAC,aAAa;;kFATb,qBAAqB","sourcesContent":["import {\n AfterViewInit,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n Output,\n ViewChild\n} from '@angular/core';\nimport { MJNamedControlBase } from '../a11y/named-control.base';\nimport { WarnIfUnnamed } from '../a11y/unnamed-control-guard';\n\n/**\n * mj-page-search — Canonical in-page search input for dashboard headers and toolbars.\n * Replaces per-page `.search-input-wrapper` rules so styling can't drift.\n *\n * Distinct from `mj-search-input` (the navbar/global search in `@memberjunction/ng-search`)\n * — this one is a simple text input used for filtering page content.\n *\n * The `Placeholder` is the accessible name of last resort — it is what the name computation falls\n * back to, and it disappears the moment the user types. Pass\n * {@link MJNamedControlBase.AriaLabel} (or {@link MJNamedControlBase.AriaLabelledBy} when a visible\n * label exists) so the box has a name that survives having text in it. The control is a real\n * `<input>`, so {@link MJNamedControlBase.InputId} IS a valid `<label for>` target.\n *\n * Example:\n * ```html\n * <mj-page-search\n * AriaLabel=\"Search templates\"\n * Placeholder=\"Search templates...\"\n * [Value]=\"searchTerm\"\n * (ValueChange)=\"onSearch($event)\">\n * </mj-page-search>\n * ```\n */\n@Component({\n selector: 'mj-page-search',\n standalone: true,\n template: `\n <div class=\"mj-page-search\" [class.mj-page-search--focused]=\"focused\">\n <!-- Decorative: the magnifier repeats what the name and placeholder already say. -->\n <i [class]=\"Icon\" aria-hidden=\"true\"></i>\n <input\n #searchInput\n type=\"text\"\n [attr.id]=\"InputId || null\"\n [attr.aria-label]=\"AriaLabel || null\"\n [attr.aria-labelledby]=\"AriaLabelledBy || null\"\n [attr.aria-describedby]=\"AriaDescribedBy || null\"\n [placeholder]=\"Placeholder\"\n [value]=\"Value\"\n (input)=\"onInput($event)\"\n (focus)=\"focused = true\"\n (blur)=\"focused = false\" />\n </div>\n `,\n styles: [`\n :host {\n display: inline-flex;\n min-width: 220px;\n }\n\n /* Compact toolbar density (32px) to match mjButton size=\"sm\" and other\n header widgets. White background + border-default for visual differentiation\n on both the page-header (white) and body (sunken) surfaces.\n Note: this is intentionally tighter than .mj-input (38px) because\n mj-page-search is a toolbar widget, not a form field. */\n .mj-page-search {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n width: 100%;\n padding: var(--mj-space-1) var(--mj-space-3);\n font-family: var(--mj-font-family);\n font-size: var(--mj-text-sm);\n line-height: 1.5;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n transition: var(--mj-transition-colors), box-shadow var(--mj-transition-base);\n min-height: 32px;\n box-sizing: border-box;\n }\n\n .mj-page-search:hover {\n border-color: var(--mj-border-strong);\n }\n\n .mj-page-search--focused {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-focus-ring);\n }\n\n .mj-page-search i {\n color: var(--mj-text-muted);\n font-size: 13px;\n flex-shrink: 0;\n }\n\n .mj-page-search input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n font: inherit;\n color: var(--mj-text-primary);\n min-width: 0;\n }\n\n .mj-page-search input::placeholder {\n color: var(--mj-text-disabled);\n }\n `]\n})\nexport class MJPageSearchComponent extends MJNamedControlBase implements AfterViewInit {\n /** The placeholder a caller gets by having said nothing — it names no particular search. */\n static readonly GenericPlaceholder = 'Search...';\n\n @Input() Placeholder: string = MJPageSearchComponent.GenericPlaceholder;\n @Input() Value: string = '';\n @Input() Icon: string = 'fa-solid fa-search';\n @Output() ValueChange = new EventEmitter<string>();\n\n @ViewChild('searchInput') private searchInputEl: ElementRef<HTMLInputElement> | undefined;\n\n public Focused: boolean = false;\n\n /** @deprecated Use {@link Focused}. */\n public get focused(): boolean {\n return this.Focused;\n }\n /** @deprecated Use {@link Focused}. */\n public set focused(value: boolean) {\n this.Focused = value;\n }\n\n /**\n * `PlaceholderIsName` is passed here and nowhere else: this is a toolbar widget whose placeholder\n * (\"Search templates…\") IS the caller's statement of what the box searches. On a form control a\n * placeholder is not a name — it disappears as soon as the user types — so those controls warn\n * without one.\n *\n * It is not passed unconditionally, or the guard could never fire here at all: the default\n * placeholder is non-empty, so accepting any placeholder would accept `'Search...'`, which tells a\n * screen-reader user nothing about what is being searched. Only a placeholder the caller actually\n * chose counts.\n */\n public ngAfterViewInit(): void {\n WarnIfUnnamed(this.searchInputEl?.nativeElement, 'mj-page-search', {\n PlaceholderIsName: this.Placeholder !== MJPageSearchComponent.GenericPlaceholder\n });\n }\n\n public OnInput(event: Event): void {\n const v = (event.target as HTMLInputElement).value;\n this.Value = v;\n this.ValueChange.emit(v);\n }\n\n /** @deprecated Use {@link OnInput}. */\n public onInput(event: Event): void {\n return this.OnInput(event);\n }\n}\n"]}
@@ -1,9 +1,28 @@
1
+ import { AfterViewInit } from '@angular/core';
1
2
  import { ControlValueAccessor } from '@angular/forms';
3
+ import { MJNamedControlBase } from '../a11y/named-control.base';
2
4
  import * as i0 from "@angular/core";
3
5
  /**
4
6
  * mj-switch — Toggle switch. Replaces `<kendo-switch>`.
7
+ *
8
+ * Every switch needs an ACCESSIBLE NAME. Without one it announces as "switch, on" — or, worse, as
9
+ * its own STATE, because `OnLabel`/`OffLabel` render inside the button and a `role=switch` takes
10
+ * its name from its contents when nothing else names it: a toggle labelled "On" that announces
11
+ * "On, switch, on" says nothing about what it toggles (WCAG 2.1 4.1.2). Use
12
+ * {@link MJNamedControlBase.AriaLabelledBy} when a visible label exists,
13
+ * {@link MJNamedControlBase.AriaLabel} when none does; either one overrides that state text.
14
+ *
15
+ * The switch is a `<button>`, which IS a labelable element, so
16
+ * {@link MJNamedControlBase.InputId} doubles as a `<label for>` target: the label names the switch
17
+ * — overriding the On/Off text, since an associated label outranks an element's own contents — and
18
+ * clicking it focuses and toggles the switch, which `AriaLabelledBy` alone does not give you.
19
+ *
20
+ * @example
21
+ * ```html
22
+ * <mj-switch AriaLabel="Email notifications" [(ngModel)]="isEnabled" OnLabel="On" OffLabel="Off" />
23
+ * ```
5
24
  */
6
- export declare class MJSwitchComponent implements ControlValueAccessor {
25
+ export declare class MJSwitchComponent extends MJNamedControlBase implements ControlValueAccessor, AfterViewInit {
7
26
  OnLabel: string;
8
27
  OffLabel: string;
9
28
  /**
@@ -15,6 +34,7 @@ export declare class MJSwitchComponent implements ControlValueAccessor {
15
34
  set Disabled(value: boolean);
16
35
  get Disabled(): boolean;
17
36
  readonly hostClass = true;
37
+ private switchButtonEl;
18
38
  Value: boolean;
19
39
  /** The gate on `Toggle()` — true when EITHER source says so. Assign only via `syncDisabled()`. */
20
40
  IsDisabled: boolean;
@@ -33,6 +53,7 @@ export declare class MJSwitchComponent implements ControlValueAccessor {
33
53
  * whatever the first compose produced and every later change to the input was dropped.
34
54
  */
35
55
  private syncDisabled;
56
+ ngAfterViewInit(): void;
36
57
  Toggle(): void;
37
58
  OnTouched(): void;
38
59
  writeValue(value: boolean): void;
@@ -1 +1 @@
1
- {"version":3,"file":"switch.component.d.ts","sourceRoot":"","sources":["../../../src/lib/switch/switch.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;;AAEzE;;GAEG;AACH,qBAgBa,iBAAkB,YAAW,oBAAoB;IACnD,OAAO,SAAM;IACb,QAAQ,SAAM;IACvB;;;;;OAKG;IACH,IACI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAsD;IACjF,IAAI,QAAQ,IAAI,OAAO,CAA+B;IACjB,QAAQ,CAAC,SAAS,QAAQ;IAE/D,KAAK,UAAS;IACd,kGAAkG;IAClG,UAAU,UAAS;IACnB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,QAAQ,CAAsC;IACtD,OAAO,CAAC,SAAS,CAAwB;IAEzC;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IAOpB,MAAM,IAAI,IAAI;IACd,SAAS,IAAI,IAAI;IACjB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAChC,gBAAgB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IACpD,iBAAiB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IACvC,gBAAgB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI;yCA5ChC,iBAAiB;2CAAjB,iBAAiB;CA6C7B"}
1
+ {"version":3,"file":"switch.component.d.ts","sourceRoot":"","sources":["../../../src/lib/switch/switch.component.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EASd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAqB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;;AAGhE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAoBa,iBAAkB,SAAQ,kBAAmB,YAAW,oBAAoB,EAAE,aAAa;IAC7F,OAAO,SAAM;IACb,QAAQ,SAAM;IACvB;;;;;OAKG;IACH,IACI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAsD;IACjF,IAAI,QAAQ,IAAI,OAAO,CAA+B;IACjB,QAAQ,CAAC,SAAS,QAAQ;IACpC,OAAO,CAAC,cAAc,CAA4C;IAE7F,KAAK,UAAS;IACd,kGAAkG;IAClG,UAAU,UAAS;IACnB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,QAAQ,CAAsC;IACtD,OAAO,CAAC,SAAS,CAAwB;IAEzC;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IAOpB,eAAe,IAAI,IAAI;IAEvB,MAAM,IAAI,IAAI;IACd,SAAS,IAAI,IAAI;IACjB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAChC,gBAAgB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IACpD,iBAAiB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IACvC,gBAAgB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI;yCA/ChC,iBAAiB;2CAAjB,iBAAiB;CAgD7B"}