@unabridged/midwest 0.21.0 → 0.22.0
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/app/assets/javascript/midwest/index.ts +8 -2
- package/app/assets/javascript/midwest.js +725 -20
- package/app/assets/javascript/midwest.js.map +1 -1
- package/app/assets/stylesheets/midwest.css +1 -1
- package/app/assets/stylesheets/midwest.tailwind.css +6 -1
- package/dist/css/midwest.css +1 -1
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js +8 -2
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/code_block_component/code_block_component_controller.js +17 -0
- package/dist/javascript/collection/app/components/midwest/code_block_component/code_block_component_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/dialog_component/dialog_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/form/date_picker_component/date_picker_component_controller.js +243 -0
- package/dist/javascript/collection/app/components/midwest/form/date_picker_component/date_picker_component_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/form/file_component/file_component_controller.js +35 -1
- package/dist/javascript/collection/app/components/midwest/form/file_component/file_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/form/input_component/input_component_controller.js +72 -2
- package/dist/javascript/collection/app/components/midwest/form/input_component/input_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js +12 -0
- package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/form/time_picker_component/time_picker_component_controller.js +164 -0
- package/dist/javascript/collection/app/components/midwest/form/time_picker_component/time_picker_component_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/password_requirements_component/password_requirements_component_controller.js +194 -0
- package/dist/javascript/collection/app/components/midwest/password_requirements_component/password_requirements_component_controller.js.map +1 -0
- package/dist/javascript/midwest.js +725 -20
- package/dist/javascript/midwest.js.map +1 -1
- package/package.json +1 -1
|
@@ -569,10 +569,11 @@ const FORMATTERS = {
|
|
|
569
569
|
}
|
|
570
570
|
};
|
|
571
571
|
class Input extends Controller {
|
|
572
|
-
static targets = ["input", "counter", "capsLockWarning", "matchError"];
|
|
572
|
+
static targets = ["input", "counter", "capsLockWarning", "matchError", "validationError", "validationMessage"];
|
|
573
573
|
static values = {
|
|
574
574
|
match: { type: String, default: "" },
|
|
575
|
-
autoformat: { type: String, default: "" }
|
|
575
|
+
autoformat: { type: String, default: "" },
|
|
576
|
+
validate: { type: Boolean, default: false }
|
|
576
577
|
};
|
|
577
578
|
updateClearButton = null;
|
|
578
579
|
updateCounter = null;
|
|
@@ -583,6 +584,10 @@ class Input extends Controller {
|
|
|
583
584
|
matchSourceListener = null;
|
|
584
585
|
matchSourceElement = null;
|
|
585
586
|
autoformatListener = null;
|
|
587
|
+
validateBlurListener = null;
|
|
588
|
+
validateInputListener = null;
|
|
589
|
+
validateInvalidListener = null;
|
|
590
|
+
hasTouched = false;
|
|
586
591
|
connect() {
|
|
587
592
|
this.applyColor();
|
|
588
593
|
this.applySearchClear();
|
|
@@ -590,6 +595,7 @@ class Input extends Controller {
|
|
|
590
595
|
this.applyPassword();
|
|
591
596
|
this.applyMatch();
|
|
592
597
|
this.applyAutoformat();
|
|
598
|
+
this.applyValidation();
|
|
593
599
|
}
|
|
594
600
|
disconnect() {
|
|
595
601
|
if (this.updateClearButton) {
|
|
@@ -628,6 +634,18 @@ class Input extends Controller {
|
|
|
628
634
|
this.inputTarget.removeEventListener("blur", this.autoformatListener);
|
|
629
635
|
this.autoformatListener = null;
|
|
630
636
|
}
|
|
637
|
+
if (this.validateBlurListener) {
|
|
638
|
+
this.inputTarget.removeEventListener("blur", this.validateBlurListener);
|
|
639
|
+
this.validateBlurListener = null;
|
|
640
|
+
}
|
|
641
|
+
if (this.validateInputListener) {
|
|
642
|
+
this.inputTarget.removeEventListener("input", this.validateInputListener);
|
|
643
|
+
this.validateInputListener = null;
|
|
644
|
+
}
|
|
645
|
+
if (this.validateInvalidListener) {
|
|
646
|
+
this.inputTarget.removeEventListener("invalid", this.validateInvalidListener);
|
|
647
|
+
this.validateInvalidListener = null;
|
|
648
|
+
}
|
|
631
649
|
}
|
|
632
650
|
increment() {
|
|
633
651
|
const input = this.inputTarget;
|
|
@@ -788,10 +806,63 @@ class Input extends Controller {
|
|
|
788
806
|
};
|
|
789
807
|
this.inputTarget.addEventListener("blur", this.autoformatListener);
|
|
790
808
|
}
|
|
809
|
+
// Shopify-style inline validation: validates on blur using the HTML5
|
|
810
|
+
// Constraint Validation API. Errors are shown inline after the first
|
|
811
|
+
// blur ("touched"), then re-validated on each input keystroke so the
|
|
812
|
+
// error clears as soon as the field becomes valid.
|
|
813
|
+
applyValidation() {
|
|
814
|
+
if (!this.validateValue)
|
|
815
|
+
return;
|
|
816
|
+
const showValidationError = (message) => {
|
|
817
|
+
this.element.classList.add("has-error", "theme-red");
|
|
818
|
+
this.element.classList.remove("is-valid");
|
|
819
|
+
if (this.hasValidationErrorTarget)
|
|
820
|
+
this.validationErrorTarget.hidden = false;
|
|
821
|
+
if (this.hasValidationMessageTarget)
|
|
822
|
+
this.validationMessageTarget.textContent = message;
|
|
823
|
+
};
|
|
824
|
+
const clearValidationError = () => {
|
|
825
|
+
this.element.classList.remove("has-error", "theme-red");
|
|
826
|
+
if (this.hasValidationErrorTarget)
|
|
827
|
+
this.validationErrorTarget.hidden = true;
|
|
828
|
+
if (this.hasValidationMessageTarget)
|
|
829
|
+
this.validationMessageTarget.textContent = "";
|
|
830
|
+
if (this.inputTarget.value) {
|
|
831
|
+
this.element.classList.add("is-valid");
|
|
832
|
+
} else {
|
|
833
|
+
this.element.classList.remove("is-valid");
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
const validate = () => {
|
|
837
|
+
if (!this.inputTarget.checkValidity()) {
|
|
838
|
+
showValidationError(this.inputTarget.validationMessage);
|
|
839
|
+
} else {
|
|
840
|
+
clearValidationError();
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
this.validateBlurListener = () => {
|
|
844
|
+
this.hasTouched = true;
|
|
845
|
+
validate();
|
|
846
|
+
};
|
|
847
|
+
this.validateInputListener = () => {
|
|
848
|
+
if (!this.hasTouched)
|
|
849
|
+
return;
|
|
850
|
+
validate();
|
|
851
|
+
};
|
|
852
|
+
this.validateInvalidListener = (e) => {
|
|
853
|
+
e.preventDefault();
|
|
854
|
+
this.hasTouched = true;
|
|
855
|
+
showValidationError(this.inputTarget.validationMessage);
|
|
856
|
+
};
|
|
857
|
+
this.inputTarget.addEventListener("blur", this.validateBlurListener);
|
|
858
|
+
this.inputTarget.addEventListener("input", this.validateInputListener);
|
|
859
|
+
this.inputTarget.addEventListener("invalid", this.validateInvalidListener);
|
|
860
|
+
}
|
|
791
861
|
}
|
|
792
862
|
|
|
793
863
|
class File extends Controller {
|
|
794
|
-
static targets = ["input", "output"];
|
|
864
|
+
static targets = ["input", "output", "dropzone"];
|
|
865
|
+
dragCounter = 0;
|
|
795
866
|
// Arrow function so `this` is stable for add/removeEventListener pairing.
|
|
796
867
|
handleChange = () => {
|
|
797
868
|
this.renderPreviews();
|
|
@@ -801,8 +872,41 @@ class File extends Controller {
|
|
|
801
872
|
}
|
|
802
873
|
disconnect() {
|
|
803
874
|
this.inputTarget.removeEventListener("change", this.handleChange);
|
|
875
|
+
this.dragCounter = 0;
|
|
876
|
+
}
|
|
877
|
+
// --- Drag-and-drop ---
|
|
878
|
+
dragenter(e) {
|
|
879
|
+
e.preventDefault();
|
|
880
|
+
this.dragCounter++;
|
|
881
|
+
this.dropzoneTarget.classList.add("is-dragover");
|
|
882
|
+
}
|
|
883
|
+
dragover(e) {
|
|
884
|
+
e.preventDefault();
|
|
885
|
+
}
|
|
886
|
+
dragleave(e) {
|
|
887
|
+
e.preventDefault();
|
|
888
|
+
this.dragCounter--;
|
|
889
|
+
if (this.dragCounter <= 0) {
|
|
890
|
+
this.dragCounter = 0;
|
|
891
|
+
this.dropzoneTarget.classList.remove("is-dragover");
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
drop(e) {
|
|
895
|
+
e.preventDefault();
|
|
896
|
+
this.dragCounter = 0;
|
|
897
|
+
this.dropzoneTarget.classList.remove("is-dragover");
|
|
898
|
+
if (!e.dataTransfer?.files.length)
|
|
899
|
+
return;
|
|
900
|
+
this.inputTarget.files = e.dataTransfer.files;
|
|
901
|
+
this.inputTarget.dispatchEvent(new Event("change", { bubbles: true }));
|
|
902
|
+
}
|
|
903
|
+
browse() {
|
|
904
|
+
this.inputTarget.click();
|
|
804
905
|
}
|
|
906
|
+
// --- Preview rendering ---
|
|
805
907
|
renderPreviews() {
|
|
908
|
+
if (!this.hasOutputTarget)
|
|
909
|
+
return;
|
|
806
910
|
this.outputTarget.innerHTML = "";
|
|
807
911
|
this.files.forEach((file) => {
|
|
808
912
|
this.outputTarget.appendChild(this.buildPreview(file));
|
|
@@ -3314,6 +3418,18 @@ class FormLiveSummary extends Controller {
|
|
|
3314
3418
|
const selected = Array.from(ac.querySelectorAll(".midwest-autocomplete-tokens .value")).map((el) => el.textContent?.trim()).filter(Boolean).join(", ");
|
|
3315
3419
|
fields.push({ label, value: selected || "\u2014" });
|
|
3316
3420
|
});
|
|
3421
|
+
form.querySelectorAll(".midwest-date-picker").forEach((picker) => {
|
|
3422
|
+
if (this.element.contains(picker))
|
|
3423
|
+
return;
|
|
3424
|
+
const input = picker.querySelector('[data-midwest-date-picker-target="input"]');
|
|
3425
|
+
if (!input?.name)
|
|
3426
|
+
return;
|
|
3427
|
+
const labelEl = picker.querySelector(".midwest-form-group__top label");
|
|
3428
|
+
const label = labelEl?.textContent?.trim() || this.prettifyName(input.name.replace(/\[.*\]$/, ""));
|
|
3429
|
+
const display = picker.querySelector('[data-midwest-date-picker-target="display"] .value');
|
|
3430
|
+
const value = display?.textContent?.trim() || "";
|
|
3431
|
+
fields.push({ label, value: value || "\u2014" });
|
|
3432
|
+
});
|
|
3317
3433
|
const seenTreeNames = /* @__PURE__ */ new Set();
|
|
3318
3434
|
form.querySelectorAll(".midwest-tree-view").forEach((tree) => {
|
|
3319
3435
|
if (this.element.contains(tree))
|
|
@@ -3502,22 +3618,6 @@ class ConfirmationController extends Controller {
|
|
|
3502
3618
|
}
|
|
3503
3619
|
}
|
|
3504
3620
|
|
|
3505
|
-
class AvatarGroup extends Controller {
|
|
3506
|
-
static targets = ["overflow", "hidden"];
|
|
3507
|
-
expand() {
|
|
3508
|
-
this.element.classList.add("is-expanding");
|
|
3509
|
-
this.hiddenTargets.forEach((wrapper) => {
|
|
3510
|
-
wrapper.classList.add("is-visible");
|
|
3511
|
-
});
|
|
3512
|
-
if (this.hasOverflowTarget) {
|
|
3513
|
-
this.overflowTarget.classList.add("avatar-overflow-hiding");
|
|
3514
|
-
this.overflowTarget.addEventListener("transitionend", () => {
|
|
3515
|
-
this.overflowTarget.remove();
|
|
3516
|
-
}, { once: true });
|
|
3517
|
-
}
|
|
3518
|
-
}
|
|
3519
|
-
}
|
|
3520
|
-
|
|
3521
3621
|
class Chart extends Controller {
|
|
3522
3622
|
static targets = ["tooltip", "svg"];
|
|
3523
3623
|
static values = { tooltipEnabled: { type: Boolean, default: true } };
|
|
@@ -5853,6 +5953,608 @@ class Repeatable extends Controller {
|
|
|
5853
5953
|
}
|
|
5854
5954
|
}
|
|
5855
5955
|
|
|
5956
|
+
const VALIDATORS = {
|
|
5957
|
+
min_length: (v, n) => v.length >= n,
|
|
5958
|
+
uppercase: (v, n) => (v.match(/[A-Z]/g) || []).length >= n,
|
|
5959
|
+
lowercase: (v, n) => (v.match(/[a-z]/g) || []).length >= n,
|
|
5960
|
+
number: (v, n) => (v.match(/[0-9]/g) || []).length >= n,
|
|
5961
|
+
special: (v, n) => (v.match(/[^A-Za-z0-9]/g) || []).length >= n
|
|
5962
|
+
};
|
|
5963
|
+
class PasswordRequirements extends Controller {
|
|
5964
|
+
static targets = ["requirement", "list", "complete", "strength", "strengthLabel", "inline", "panel"];
|
|
5965
|
+
static values = {
|
|
5966
|
+
input: { type: String, default: "" },
|
|
5967
|
+
anchored: { type: Boolean, default: false },
|
|
5968
|
+
anchorName: { type: String, default: "" },
|
|
5969
|
+
inline: { type: Boolean, default: false },
|
|
5970
|
+
inlineAnchorName: { type: String, default: "" }
|
|
5971
|
+
};
|
|
5972
|
+
sourceElement = null;
|
|
5973
|
+
inputListener = null;
|
|
5974
|
+
focusListener = null;
|
|
5975
|
+
blurListener = null;
|
|
5976
|
+
connect() {
|
|
5977
|
+
if (!this.inputValue)
|
|
5978
|
+
return;
|
|
5979
|
+
this.sourceElement = document.querySelector(this.inputValue);
|
|
5980
|
+
if (!this.sourceElement)
|
|
5981
|
+
return;
|
|
5982
|
+
this.inputListener = () => this.validate();
|
|
5983
|
+
this.sourceElement.addEventListener("input", this.inputListener);
|
|
5984
|
+
this.applyAnchorNames();
|
|
5985
|
+
if (this.inlineValue) {
|
|
5986
|
+
this.sourceElement.classList.add("has-inline-password-requirements");
|
|
5987
|
+
}
|
|
5988
|
+
if (this.anchoredValue) {
|
|
5989
|
+
this.applyAnchor();
|
|
5990
|
+
}
|
|
5991
|
+
this.validate();
|
|
5992
|
+
}
|
|
5993
|
+
disconnect() {
|
|
5994
|
+
if (this.sourceElement) {
|
|
5995
|
+
if (this.inputListener)
|
|
5996
|
+
this.sourceElement.removeEventListener("input", this.inputListener);
|
|
5997
|
+
if (this.focusListener)
|
|
5998
|
+
this.sourceElement.removeEventListener("focus", this.focusListener);
|
|
5999
|
+
if (this.blurListener)
|
|
6000
|
+
this.sourceElement.removeEventListener("blur", this.blurListener);
|
|
6001
|
+
if (this.anchoredValue || this.inlineValue) {
|
|
6002
|
+
this.sourceElement.style.removeProperty("anchor-name");
|
|
6003
|
+
}
|
|
6004
|
+
if (this.inlineValue) {
|
|
6005
|
+
this.sourceElement.classList.remove("has-inline-password-requirements");
|
|
6006
|
+
}
|
|
6007
|
+
}
|
|
6008
|
+
this.inputListener = null;
|
|
6009
|
+
this.focusListener = null;
|
|
6010
|
+
this.blurListener = null;
|
|
6011
|
+
this.sourceElement = null;
|
|
6012
|
+
}
|
|
6013
|
+
applyAnchorNames() {
|
|
6014
|
+
if (!this.sourceElement)
|
|
6015
|
+
return;
|
|
6016
|
+
const names = [];
|
|
6017
|
+
if (this.anchoredValue && this.anchorNameValue)
|
|
6018
|
+
names.push(this.anchorNameValue);
|
|
6019
|
+
if (this.inlineValue && this.inlineAnchorNameValue)
|
|
6020
|
+
names.push(this.inlineAnchorNameValue);
|
|
6021
|
+
if (names.length > 0) {
|
|
6022
|
+
this.sourceElement.style.setProperty("anchor-name", names.join(", "));
|
|
6023
|
+
}
|
|
6024
|
+
}
|
|
6025
|
+
applyAnchor() {
|
|
6026
|
+
if (!this.sourceElement || !this.anchorNameValue)
|
|
6027
|
+
return;
|
|
6028
|
+
this.focusListener = () => this.showPopover();
|
|
6029
|
+
this.blurListener = () => this.hidePopover();
|
|
6030
|
+
this.sourceElement.addEventListener("focus", this.focusListener);
|
|
6031
|
+
this.sourceElement.addEventListener("blur", this.blurListener);
|
|
6032
|
+
if (document.activeElement === this.sourceElement) {
|
|
6033
|
+
this.showPopover();
|
|
6034
|
+
}
|
|
6035
|
+
}
|
|
6036
|
+
get popoverElement() {
|
|
6037
|
+
return this.hasPanelTarget ? this.panelTarget : this.element;
|
|
6038
|
+
}
|
|
6039
|
+
showPopover() {
|
|
6040
|
+
try {
|
|
6041
|
+
this.popoverElement.showPopover?.();
|
|
6042
|
+
} catch {
|
|
6043
|
+
}
|
|
6044
|
+
}
|
|
6045
|
+
hidePopover() {
|
|
6046
|
+
try {
|
|
6047
|
+
this.popoverElement.hidePopover?.();
|
|
6048
|
+
} catch {
|
|
6049
|
+
}
|
|
6050
|
+
}
|
|
6051
|
+
validate() {
|
|
6052
|
+
const value = this.sourceElement?.value ?? "";
|
|
6053
|
+
let allMet = true;
|
|
6054
|
+
let metCount = 0;
|
|
6055
|
+
const total = this.requirementTargets.length;
|
|
6056
|
+
this.requirementTargets.forEach((li) => {
|
|
6057
|
+
const type = li.dataset.requirementType ?? "";
|
|
6058
|
+
let met = false;
|
|
6059
|
+
if (type === "pattern") {
|
|
6060
|
+
const pattern = li.dataset.requirementPattern;
|
|
6061
|
+
if (pattern) {
|
|
6062
|
+
try {
|
|
6063
|
+
met = new RegExp(pattern).test(value);
|
|
6064
|
+
} catch {
|
|
6065
|
+
met = false;
|
|
6066
|
+
}
|
|
6067
|
+
}
|
|
6068
|
+
} else {
|
|
6069
|
+
const count = parseInt(li.dataset.requirementCount ?? "1", 10);
|
|
6070
|
+
const validator = VALIDATORS[type];
|
|
6071
|
+
met = validator ? validator(value, count) : false;
|
|
6072
|
+
}
|
|
6073
|
+
li.classList.toggle("is-met", met);
|
|
6074
|
+
const label = li.querySelector(".requirement-label")?.textContent ?? "";
|
|
6075
|
+
li.setAttribute("aria-label", `${label}: ${met ? "met" : "not met"}`);
|
|
6076
|
+
if (met)
|
|
6077
|
+
metCount++;
|
|
6078
|
+
if (!met)
|
|
6079
|
+
allMet = false;
|
|
6080
|
+
});
|
|
6081
|
+
const complete = allMet && value.length > 0;
|
|
6082
|
+
this.popoverElement.classList.toggle("is-complete", complete);
|
|
6083
|
+
if (this.hasListTarget)
|
|
6084
|
+
this.listTarget.hidden = complete;
|
|
6085
|
+
if (this.hasCompleteTarget)
|
|
6086
|
+
this.completeTarget.hidden = !complete;
|
|
6087
|
+
if (this.hasStrengthTarget)
|
|
6088
|
+
this.updateStrength(metCount, total, value.length > 0);
|
|
6089
|
+
if (this.inlineValue)
|
|
6090
|
+
this.updateInlineIndicator(metCount, total, value.length > 0);
|
|
6091
|
+
}
|
|
6092
|
+
updateStrength(met, total, hasValue) {
|
|
6093
|
+
const percentage = total > 0 && hasValue ? Math.round(met / total * 100) : 0;
|
|
6094
|
+
const fill = this.strengthTarget.querySelector(".progress-fill");
|
|
6095
|
+
const track = this.strengthTarget.querySelector('[role="progressbar"]');
|
|
6096
|
+
if (fill)
|
|
6097
|
+
fill.style.width = `${percentage}%`;
|
|
6098
|
+
if (track)
|
|
6099
|
+
track.setAttribute("aria-valuenow", String(percentage));
|
|
6100
|
+
let state = "danger";
|
|
6101
|
+
let label = "Weak";
|
|
6102
|
+
if (percentage >= 100) {
|
|
6103
|
+
state = "success";
|
|
6104
|
+
label = "Strong";
|
|
6105
|
+
} else if (percentage >= 60) {
|
|
6106
|
+
state = "alert";
|
|
6107
|
+
label = "Fair";
|
|
6108
|
+
}
|
|
6109
|
+
const meter = this.strengthTarget.querySelector(".midwest-progress-bar");
|
|
6110
|
+
if (meter) {
|
|
6111
|
+
meter.classList.remove("theme-red", "theme-yellow", "theme-green");
|
|
6112
|
+
const themeClass = { danger: "theme-red", alert: "theme-yellow", success: "theme-green" }[state];
|
|
6113
|
+
if (themeClass)
|
|
6114
|
+
meter.classList.add(themeClass);
|
|
6115
|
+
}
|
|
6116
|
+
if (this.hasStrengthLabelTarget) {
|
|
6117
|
+
this.strengthLabelTarget.textContent = label;
|
|
6118
|
+
}
|
|
6119
|
+
}
|
|
6120
|
+
updateInlineIndicator(met, total, hasValue) {
|
|
6121
|
+
if (!this.hasInlineTarget)
|
|
6122
|
+
return;
|
|
6123
|
+
const el = this.inlineTarget;
|
|
6124
|
+
const percentage = total > 0 && hasValue ? Math.round(met / total * 100) : 0;
|
|
6125
|
+
const fill = el.querySelector(".progress-circular-fill");
|
|
6126
|
+
const svg = el.querySelector('[role="progressbar"]');
|
|
6127
|
+
if (fill) {
|
|
6128
|
+
const r = parseFloat(fill.getAttribute("r") ?? "0");
|
|
6129
|
+
const circumference = 2 * Math.PI * r;
|
|
6130
|
+
const offset = circumference * (1 - percentage / 100);
|
|
6131
|
+
fill.setAttribute("stroke-dashoffset", String(offset));
|
|
6132
|
+
}
|
|
6133
|
+
if (svg)
|
|
6134
|
+
svg.setAttribute("aria-valuenow", String(percentage));
|
|
6135
|
+
let themeClass = "theme-red";
|
|
6136
|
+
if (percentage >= 100) {
|
|
6137
|
+
themeClass = "theme-green";
|
|
6138
|
+
} else if (percentage >= 60) {
|
|
6139
|
+
themeClass = "theme-yellow";
|
|
6140
|
+
}
|
|
6141
|
+
el.classList.remove("theme-red", "theme-yellow", "theme-green");
|
|
6142
|
+
el.classList.add(themeClass);
|
|
6143
|
+
}
|
|
6144
|
+
}
|
|
6145
|
+
|
|
6146
|
+
class CodeBlock extends Controller {
|
|
6147
|
+
static targets = ["source"];
|
|
6148
|
+
async copy() {
|
|
6149
|
+
const text = this.sourceTarget.textContent || "";
|
|
6150
|
+
await navigator.clipboard.writeText(text.trim());
|
|
6151
|
+
const button = this.element.querySelector(".code-block-copy");
|
|
6152
|
+
if (!button)
|
|
6153
|
+
return;
|
|
6154
|
+
button.classList.add("is-copied");
|
|
6155
|
+
setTimeout(() => button.classList.remove("is-copied"), 2e3);
|
|
6156
|
+
}
|
|
6157
|
+
}
|
|
6158
|
+
|
|
6159
|
+
class DatePicker extends Controller {
|
|
6160
|
+
static targets = ["input", "display", "trigger", "popover", "grid", "monthLabel"];
|
|
6161
|
+
static values = {
|
|
6162
|
+
month: String,
|
|
6163
|
+
min: String,
|
|
6164
|
+
max: String
|
|
6165
|
+
};
|
|
6166
|
+
currentMonth = /* @__PURE__ */ new Date();
|
|
6167
|
+
connect() {
|
|
6168
|
+
if (this.monthValue) {
|
|
6169
|
+
this.currentMonth = this.parseDate(this.monthValue) || /* @__PURE__ */ new Date();
|
|
6170
|
+
}
|
|
6171
|
+
this.popoverTarget.addEventListener("toggle", this.handleToggle);
|
|
6172
|
+
this.gridTarget.addEventListener("keydown", this.handleGridKeydown);
|
|
6173
|
+
}
|
|
6174
|
+
disconnect() {
|
|
6175
|
+
this.popoverTarget.removeEventListener("toggle", this.handleToggle);
|
|
6176
|
+
this.gridTarget.removeEventListener("keydown", this.handleGridKeydown);
|
|
6177
|
+
}
|
|
6178
|
+
toggle() {
|
|
6179
|
+
this.popoverTarget.togglePopover();
|
|
6180
|
+
}
|
|
6181
|
+
handleToggle = (event) => {
|
|
6182
|
+
const popover = event.target;
|
|
6183
|
+
const open = popover.matches(":popover-open");
|
|
6184
|
+
this.triggerTarget.setAttribute("aria-expanded", String(open));
|
|
6185
|
+
if (open) {
|
|
6186
|
+
requestAnimationFrame(() => this.focusGridDate());
|
|
6187
|
+
} else {
|
|
6188
|
+
this.triggerTarget.focus();
|
|
6189
|
+
}
|
|
6190
|
+
};
|
|
6191
|
+
selectDate(event) {
|
|
6192
|
+
const button = event.currentTarget;
|
|
6193
|
+
const dateStr = button.dataset.date;
|
|
6194
|
+
if (!dateStr)
|
|
6195
|
+
return;
|
|
6196
|
+
this.inputTarget.value = dateStr;
|
|
6197
|
+
const date = this.parseDate(dateStr);
|
|
6198
|
+
if (date) {
|
|
6199
|
+
this.updateDisplayText(this.formatDisplay(date));
|
|
6200
|
+
this.currentMonth = new Date(date.getFullYear(), date.getMonth(), 1);
|
|
6201
|
+
this.monthValue = this.formatISO(this.currentMonth);
|
|
6202
|
+
}
|
|
6203
|
+
this.inputTarget.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6204
|
+
this.renderCalendar();
|
|
6205
|
+
this.popoverTarget.hidePopover();
|
|
6206
|
+
}
|
|
6207
|
+
selectToday() {
|
|
6208
|
+
const today = /* @__PURE__ */ new Date();
|
|
6209
|
+
const dateStr = this.formatISO(today);
|
|
6210
|
+
if (this.isDisabledDate(today))
|
|
6211
|
+
return;
|
|
6212
|
+
this.inputTarget.value = dateStr;
|
|
6213
|
+
this.updateDisplayText(this.formatDisplay(today));
|
|
6214
|
+
this.currentMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
|
6215
|
+
this.monthValue = this.formatISO(this.currentMonth);
|
|
6216
|
+
this.inputTarget.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6217
|
+
this.renderCalendar();
|
|
6218
|
+
this.popoverTarget.hidePopover();
|
|
6219
|
+
}
|
|
6220
|
+
clear() {
|
|
6221
|
+
this.inputTarget.value = "";
|
|
6222
|
+
this.updateDisplayText(this.element.dataset.placeholder || "Select a date");
|
|
6223
|
+
this.inputTarget.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6224
|
+
this.renderCalendar();
|
|
6225
|
+
this.popoverTarget.hidePopover();
|
|
6226
|
+
}
|
|
6227
|
+
prevMonth() {
|
|
6228
|
+
this.currentMonth = new Date(this.currentMonth.getFullYear(), this.currentMonth.getMonth() - 1, 1);
|
|
6229
|
+
this.monthValue = this.formatISO(this.currentMonth);
|
|
6230
|
+
this.renderCalendar();
|
|
6231
|
+
}
|
|
6232
|
+
nextMonth() {
|
|
6233
|
+
this.currentMonth = new Date(this.currentMonth.getFullYear(), this.currentMonth.getMonth() + 1, 1);
|
|
6234
|
+
this.monthValue = this.formatISO(this.currentMonth);
|
|
6235
|
+
this.renderCalendar();
|
|
6236
|
+
}
|
|
6237
|
+
// -- Keyboard navigation (WAI-ARIA grid pattern) --
|
|
6238
|
+
handleGridKeydown = (event) => {
|
|
6239
|
+
const button = event.target;
|
|
6240
|
+
if (!button.dataset?.date)
|
|
6241
|
+
return;
|
|
6242
|
+
const current = this.parseDate(button.dataset.date);
|
|
6243
|
+
if (!current)
|
|
6244
|
+
return;
|
|
6245
|
+
const next = this.nextDateForKey(event.key, current, event.shiftKey);
|
|
6246
|
+
if (!next)
|
|
6247
|
+
return;
|
|
6248
|
+
event.preventDefault();
|
|
6249
|
+
if (this.isDisabledDate(next))
|
|
6250
|
+
return;
|
|
6251
|
+
if (next.getMonth() !== this.currentMonth.getMonth() || next.getFullYear() !== this.currentMonth.getFullYear()) {
|
|
6252
|
+
this.currentMonth = new Date(next.getFullYear(), next.getMonth(), 1);
|
|
6253
|
+
this.monthValue = this.formatISO(this.currentMonth);
|
|
6254
|
+
this.renderCalendar();
|
|
6255
|
+
}
|
|
6256
|
+
this.focusButton(next);
|
|
6257
|
+
};
|
|
6258
|
+
// -- Calendar rendering --
|
|
6259
|
+
renderCalendar() {
|
|
6260
|
+
const year = this.currentMonth.getFullYear();
|
|
6261
|
+
const month = this.currentMonth.getMonth();
|
|
6262
|
+
this.monthLabelTarget.textContent = new Intl.DateTimeFormat("en-US", { month: "long", year: "numeric" }).format(this.currentMonth);
|
|
6263
|
+
const firstDay = new Date(year, month, 1);
|
|
6264
|
+
const startDate = new Date(firstDay);
|
|
6265
|
+
startDate.setDate(startDate.getDate() - startDate.getDay());
|
|
6266
|
+
const lastDay = new Date(year, month + 1, 0);
|
|
6267
|
+
const endDate = new Date(lastDay);
|
|
6268
|
+
endDate.setDate(endDate.getDate() + (6 - endDate.getDay()));
|
|
6269
|
+
const selectedValue = this.inputTarget.value;
|
|
6270
|
+
const today = this.formatISO(/* @__PURE__ */ new Date());
|
|
6271
|
+
let html = "";
|
|
6272
|
+
const cursor = new Date(startDate);
|
|
6273
|
+
while (cursor <= endDate) {
|
|
6274
|
+
html += "<tr>";
|
|
6275
|
+
for (let i = 0; i < 7; i++) {
|
|
6276
|
+
const dateStr = this.formatISO(cursor);
|
|
6277
|
+
const isOutside = cursor.getMonth() !== month;
|
|
6278
|
+
const isSelected = dateStr === selectedValue;
|
|
6279
|
+
const isToday = dateStr === today;
|
|
6280
|
+
const isDisabled = this.isDisabledDate(cursor);
|
|
6281
|
+
const classes = ["date-picker-day"];
|
|
6282
|
+
if (isOutside)
|
|
6283
|
+
classes.push("is-outside");
|
|
6284
|
+
if (isSelected)
|
|
6285
|
+
classes.push("is-selected");
|
|
6286
|
+
if (isToday)
|
|
6287
|
+
classes.push("is-today");
|
|
6288
|
+
if (isDisabled)
|
|
6289
|
+
classes.push("is-disabled");
|
|
6290
|
+
const ariaLabel = new Intl.DateTimeFormat("en-US", { month: "long", day: "numeric", year: "numeric" }).format(cursor);
|
|
6291
|
+
html += `<td role="gridcell">`;
|
|
6292
|
+
html += `<button type="button" class="${classes.join(" ")}"${isDisabled ? " disabled" : ""}`;
|
|
6293
|
+
html += ` tabindex="-1"`;
|
|
6294
|
+
html += ` data-date="${dateStr}" data-action="midwest-date-picker#selectDate"`;
|
|
6295
|
+
html += ` aria-label="${ariaLabel}"${isSelected ? ' aria-selected="true"' : ""}>`;
|
|
6296
|
+
html += `${cursor.getDate()}</button></td>`;
|
|
6297
|
+
cursor.setDate(cursor.getDate() + 1);
|
|
6298
|
+
}
|
|
6299
|
+
html += "</tr>";
|
|
6300
|
+
}
|
|
6301
|
+
this.gridTarget.innerHTML = html;
|
|
6302
|
+
this.setRovingTabindex();
|
|
6303
|
+
}
|
|
6304
|
+
// -- Focus helpers --
|
|
6305
|
+
focusGridDate() {
|
|
6306
|
+
this.setRovingTabindex();
|
|
6307
|
+
const target = this.gridTarget.querySelector('.date-picker-day[tabindex="0"]');
|
|
6308
|
+
target?.focus();
|
|
6309
|
+
}
|
|
6310
|
+
focusButton(date) {
|
|
6311
|
+
const dateStr = this.formatISO(date);
|
|
6312
|
+
const button = this.gridTarget.querySelector(`[data-date="${dateStr}"]`);
|
|
6313
|
+
if (!button)
|
|
6314
|
+
return;
|
|
6315
|
+
this.gridTarget.querySelectorAll('.date-picker-day[tabindex="0"]').forEach((b) => {
|
|
6316
|
+
b.tabIndex = -1;
|
|
6317
|
+
});
|
|
6318
|
+
button.tabIndex = 0;
|
|
6319
|
+
button.focus();
|
|
6320
|
+
}
|
|
6321
|
+
setRovingTabindex() {
|
|
6322
|
+
const selected = this.gridTarget.querySelector(".is-selected");
|
|
6323
|
+
const today = this.gridTarget.querySelector(".is-today:not(.is-outside)");
|
|
6324
|
+
const firstDay = this.gridTarget.querySelector(".date-picker-day:not(.is-outside):not(:disabled)");
|
|
6325
|
+
const target = selected || today || firstDay;
|
|
6326
|
+
if (target)
|
|
6327
|
+
target.tabIndex = 0;
|
|
6328
|
+
}
|
|
6329
|
+
nextDateForKey(key, current, shift) {
|
|
6330
|
+
switch (key) {
|
|
6331
|
+
case "ArrowRight":
|
|
6332
|
+
return this.addDays(current, 1);
|
|
6333
|
+
case "ArrowLeft":
|
|
6334
|
+
return this.addDays(current, -1);
|
|
6335
|
+
case "ArrowDown":
|
|
6336
|
+
return this.addDays(current, 7);
|
|
6337
|
+
case "ArrowUp":
|
|
6338
|
+
return this.addDays(current, -7);
|
|
6339
|
+
case "Home":
|
|
6340
|
+
return this.addDays(current, -current.getDay());
|
|
6341
|
+
case "End":
|
|
6342
|
+
return this.addDays(current, 6 - current.getDay());
|
|
6343
|
+
case "PageUp":
|
|
6344
|
+
return this.shiftMonth(current, shift ? -12 : -1);
|
|
6345
|
+
case "PageDown":
|
|
6346
|
+
return this.shiftMonth(current, shift ? 12 : 1);
|
|
6347
|
+
default:
|
|
6348
|
+
return null;
|
|
6349
|
+
}
|
|
6350
|
+
}
|
|
6351
|
+
// -- Date arithmetic --
|
|
6352
|
+
addDays(date, days) {
|
|
6353
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);
|
|
6354
|
+
}
|
|
6355
|
+
shiftMonth(date, delta) {
|
|
6356
|
+
const target = new Date(date.getFullYear(), date.getMonth() + delta, 1);
|
|
6357
|
+
const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
6358
|
+
const day = Math.min(date.getDate(), lastDay);
|
|
6359
|
+
return new Date(target.getFullYear(), target.getMonth(), day);
|
|
6360
|
+
}
|
|
6361
|
+
// -- Utilities --
|
|
6362
|
+
isDisabledDate(date) {
|
|
6363
|
+
if (this.hasMinValue) {
|
|
6364
|
+
const min = this.parseDate(this.minValue);
|
|
6365
|
+
if (min && date < min)
|
|
6366
|
+
return true;
|
|
6367
|
+
}
|
|
6368
|
+
if (this.hasMaxValue) {
|
|
6369
|
+
const max = this.parseDate(this.maxValue);
|
|
6370
|
+
if (max && date > max)
|
|
6371
|
+
return true;
|
|
6372
|
+
}
|
|
6373
|
+
return false;
|
|
6374
|
+
}
|
|
6375
|
+
parseDate(str) {
|
|
6376
|
+
const parts = str.split("-").map(Number);
|
|
6377
|
+
if (parts.length < 3)
|
|
6378
|
+
return null;
|
|
6379
|
+
return new Date(parts[0], parts[1] - 1, parts[2]);
|
|
6380
|
+
}
|
|
6381
|
+
formatISO(date) {
|
|
6382
|
+
const y = date.getFullYear();
|
|
6383
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
6384
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
6385
|
+
return `${y}-${m}-${d}`;
|
|
6386
|
+
}
|
|
6387
|
+
updateDisplayText(text) {
|
|
6388
|
+
const valueEl = this.displayTarget.querySelector(".value");
|
|
6389
|
+
if (valueEl) {
|
|
6390
|
+
valueEl.textContent = text;
|
|
6391
|
+
}
|
|
6392
|
+
}
|
|
6393
|
+
formatDisplay(date) {
|
|
6394
|
+
return new Intl.DateTimeFormat("en-US", { month: "long", day: "numeric", year: "numeric" }).format(date);
|
|
6395
|
+
}
|
|
6396
|
+
}
|
|
6397
|
+
|
|
6398
|
+
class TimePicker extends Controller {
|
|
6399
|
+
static targets = ["input", "display", "trigger", "popover", "list", "periodGroup"];
|
|
6400
|
+
static values = {
|
|
6401
|
+
step: { type: Number, default: 15 },
|
|
6402
|
+
period: { type: String, default: "AM" },
|
|
6403
|
+
min: String,
|
|
6404
|
+
max: String
|
|
6405
|
+
};
|
|
6406
|
+
selectedHour12 = null;
|
|
6407
|
+
selectedMinutes = null;
|
|
6408
|
+
connect() {
|
|
6409
|
+
this.popoverTarget.addEventListener("toggle", this.handleToggle);
|
|
6410
|
+
this.listTarget.addEventListener("keydown", this.handleKeydown);
|
|
6411
|
+
const currentValue = this.inputTarget.value;
|
|
6412
|
+
if (currentValue) {
|
|
6413
|
+
const [h, m] = currentValue.split(":").map(Number);
|
|
6414
|
+
this.periodValue = h >= 12 ? "PM" : "AM";
|
|
6415
|
+
this.selectedHour12 = h % 12 || 12;
|
|
6416
|
+
this.selectedMinutes = m;
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
disconnect() {
|
|
6420
|
+
this.popoverTarget.removeEventListener("toggle", this.handleToggle);
|
|
6421
|
+
this.listTarget.removeEventListener("keydown", this.handleKeydown);
|
|
6422
|
+
}
|
|
6423
|
+
handleToggle = (event) => {
|
|
6424
|
+
const popover = event.target;
|
|
6425
|
+
const open = popover.matches(":popover-open");
|
|
6426
|
+
this.triggerTarget.setAttribute("aria-expanded", String(open));
|
|
6427
|
+
if (open) {
|
|
6428
|
+
requestAnimationFrame(() => this.focusSelectedOption());
|
|
6429
|
+
} else {
|
|
6430
|
+
this.triggerTarget.focus();
|
|
6431
|
+
}
|
|
6432
|
+
};
|
|
6433
|
+
selectTime(event) {
|
|
6434
|
+
const option = event.currentTarget;
|
|
6435
|
+
this.selectOption(option);
|
|
6436
|
+
}
|
|
6437
|
+
setPeriod(event) {
|
|
6438
|
+
const button = event.currentTarget;
|
|
6439
|
+
const period = button.dataset.period;
|
|
6440
|
+
if (!period)
|
|
6441
|
+
return;
|
|
6442
|
+
this.periodValue = period;
|
|
6443
|
+
this.updatePeriodButtons();
|
|
6444
|
+
this.commitValue();
|
|
6445
|
+
}
|
|
6446
|
+
selectOption(option) {
|
|
6447
|
+
const hour = Number(option.dataset.hour);
|
|
6448
|
+
const minutes = Number(option.dataset.minutes);
|
|
6449
|
+
this.selectedHour12 = hour;
|
|
6450
|
+
this.selectedMinutes = minutes;
|
|
6451
|
+
this.updateSelectedOption(option);
|
|
6452
|
+
this.commitValue();
|
|
6453
|
+
this.popoverTarget.hidePopover();
|
|
6454
|
+
}
|
|
6455
|
+
commitValue() {
|
|
6456
|
+
if (this.selectedHour12 === null || this.selectedMinutes === null)
|
|
6457
|
+
return;
|
|
6458
|
+
const hour24 = this.to24h(this.selectedHour12, this.periodValue);
|
|
6459
|
+
const timeStr = `${String(hour24).padStart(2, "0")}:${String(this.selectedMinutes).padStart(2, "0")}`;
|
|
6460
|
+
this.inputTarget.value = timeStr;
|
|
6461
|
+
this.updateDisplayText(this.formatDisplay(this.selectedHour12, this.selectedMinutes, this.periodValue));
|
|
6462
|
+
this.inputTarget.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6463
|
+
}
|
|
6464
|
+
to24h(hour12, period) {
|
|
6465
|
+
if (period === "AM") {
|
|
6466
|
+
return hour12 === 12 ? 0 : hour12;
|
|
6467
|
+
}
|
|
6468
|
+
return hour12 === 12 ? 12 : hour12 + 12;
|
|
6469
|
+
}
|
|
6470
|
+
formatDisplay(hour12, minutes, period) {
|
|
6471
|
+
return `${hour12}:${String(minutes).padStart(2, "0")} ${period}`;
|
|
6472
|
+
}
|
|
6473
|
+
updatePeriodButtons() {
|
|
6474
|
+
this.periodGroupTarget.querySelectorAll(".time-picker-period-btn").forEach((btn) => {
|
|
6475
|
+
const isActive = btn.dataset.period === this.periodValue;
|
|
6476
|
+
btn.classList.toggle("is-active", isActive);
|
|
6477
|
+
btn.setAttribute("aria-checked", String(isActive));
|
|
6478
|
+
});
|
|
6479
|
+
}
|
|
6480
|
+
updateSelectedOption(selected) {
|
|
6481
|
+
this.listTarget.querySelectorAll(".time-picker-option").forEach((opt) => {
|
|
6482
|
+
const isMatch = opt === selected;
|
|
6483
|
+
opt.classList.toggle("is-selected", isMatch);
|
|
6484
|
+
opt.setAttribute("aria-selected", String(isMatch));
|
|
6485
|
+
opt.tabIndex = isMatch ? 0 : -1;
|
|
6486
|
+
});
|
|
6487
|
+
}
|
|
6488
|
+
focusSelectedOption() {
|
|
6489
|
+
const selected = this.listTarget.querySelector(".is-selected");
|
|
6490
|
+
const target = selected || this.listTarget.querySelector(".time-picker-option");
|
|
6491
|
+
if (!target)
|
|
6492
|
+
return;
|
|
6493
|
+
if (!selected) {
|
|
6494
|
+
target.tabIndex = 0;
|
|
6495
|
+
}
|
|
6496
|
+
target.focus();
|
|
6497
|
+
this.scrollToOption(target);
|
|
6498
|
+
}
|
|
6499
|
+
scrollToOption(option) {
|
|
6500
|
+
const container = this.listTarget;
|
|
6501
|
+
const optionTop = option.offsetTop;
|
|
6502
|
+
const optionHeight = option.offsetHeight;
|
|
6503
|
+
const containerHeight = container.clientHeight;
|
|
6504
|
+
const scrollTop = container.scrollTop;
|
|
6505
|
+
if (optionTop < scrollTop) {
|
|
6506
|
+
container.scrollTop = optionTop;
|
|
6507
|
+
} else if (optionTop + optionHeight > scrollTop + containerHeight) {
|
|
6508
|
+
container.scrollTop = optionTop + optionHeight - containerHeight;
|
|
6509
|
+
}
|
|
6510
|
+
}
|
|
6511
|
+
handleKeydown = (event) => {
|
|
6512
|
+
const current = event.target;
|
|
6513
|
+
if (!current.classList.contains("time-picker-option"))
|
|
6514
|
+
return;
|
|
6515
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
6516
|
+
event.preventDefault();
|
|
6517
|
+
this.selectOption(current);
|
|
6518
|
+
return;
|
|
6519
|
+
}
|
|
6520
|
+
if (event.key === "Escape") {
|
|
6521
|
+
event.preventDefault();
|
|
6522
|
+
this.popoverTarget.hidePopover();
|
|
6523
|
+
return;
|
|
6524
|
+
}
|
|
6525
|
+
const next = this.nextOptionForKey(event.key, current);
|
|
6526
|
+
if (next) {
|
|
6527
|
+
event.preventDefault();
|
|
6528
|
+
current.tabIndex = -1;
|
|
6529
|
+
next.tabIndex = 0;
|
|
6530
|
+
next.focus();
|
|
6531
|
+
this.scrollToOption(next);
|
|
6532
|
+
}
|
|
6533
|
+
};
|
|
6534
|
+
nextOptionForKey(key, current) {
|
|
6535
|
+
const options = Array.from(this.listTarget.querySelectorAll(".time-picker-option"));
|
|
6536
|
+
const index = options.indexOf(current);
|
|
6537
|
+
switch (key) {
|
|
6538
|
+
case "ArrowDown":
|
|
6539
|
+
return options[index + 1] || null;
|
|
6540
|
+
case "ArrowUp":
|
|
6541
|
+
return options[index - 1] || null;
|
|
6542
|
+
case "Home":
|
|
6543
|
+
return options[0] || null;
|
|
6544
|
+
case "End":
|
|
6545
|
+
return options[options.length - 1] || null;
|
|
6546
|
+
default:
|
|
6547
|
+
return null;
|
|
6548
|
+
}
|
|
6549
|
+
}
|
|
6550
|
+
updateDisplayText(text) {
|
|
6551
|
+
const valueEl = this.displayTarget.querySelector(".value");
|
|
6552
|
+
if (valueEl) {
|
|
6553
|
+
valueEl.textContent = text;
|
|
6554
|
+
}
|
|
6555
|
+
}
|
|
6556
|
+
}
|
|
6557
|
+
|
|
5856
6558
|
function registerMidwestControllers(application) {
|
|
5857
6559
|
application.register("midwest-card", Card);
|
|
5858
6560
|
application.register("midwest-banner", Banner);
|
|
@@ -5869,7 +6571,6 @@ function registerMidwestControllers(application) {
|
|
|
5869
6571
|
application.register("midwest-form", Form);
|
|
5870
6572
|
application.register("midwest-badge", Badge);
|
|
5871
6573
|
application.register("midwest-confirmation", ConfirmationController);
|
|
5872
|
-
application.register("midwest-avatar-group", AvatarGroup);
|
|
5873
6574
|
application.register("midwest-chart", Chart);
|
|
5874
6575
|
application.register("midwest-range", Range);
|
|
5875
6576
|
application.register("midwest-rating", Rating);
|
|
@@ -5885,6 +6586,10 @@ function registerMidwestControllers(application) {
|
|
|
5885
6586
|
application.register("midwest-tree-view", TreeView);
|
|
5886
6587
|
application.register("midwest-command-palette", CommandPalette);
|
|
5887
6588
|
application.register("midwest-repeatable", Repeatable);
|
|
6589
|
+
application.register("midwest-password-requirements", PasswordRequirements);
|
|
6590
|
+
application.register("midwest-code-block", CodeBlock);
|
|
6591
|
+
application.register("midwest-date-picker", DatePicker);
|
|
6592
|
+
application.register("midwest-time-picker", TimePicker);
|
|
5888
6593
|
}
|
|
5889
6594
|
|
|
5890
6595
|
export { Banner, Card, Chart, CountdownTimer, registerMidwestControllers };
|