@t007/input 0.0.29 → 0.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -65,6 +65,7 @@
65
65
  }
66
66
  :where(:root, .t007-input-field) {
67
67
  --t007-input-color: black;
68
+ --t007-input-inverse-color: rgb(from var(--t007-input-color) calc(255 - r) calc(255 - g) calc(255 - b));
68
69
  --t007-input-base-color: rgb(from var(--t007-input-color) r g b / 0.45);
69
70
  --t007-input-hover-color: rgb(from var(--t007-input-color) r g b / 1);
70
71
  --t007-input-focused-color: rgb(from var(--t007-input-color) r g b / 1);
@@ -117,21 +118,41 @@
117
118
  --t007-scroll-assist-width: calc(var(--t007-input-unit) * 2);
118
119
  --t007-scroll-assist-inset-x: calc(var(--t007-input-unit) * -0.25);
119
120
  --t007-scroll-assist-opacity: 0.4;
121
+ --t007-input-select-appearance: base-select;
122
+ --t007-input-select-timing: cubic-bezier(0.34, 1.56, 0.64, 1);
123
+ --t007-input-select-transition-time: 200ms;
124
+ --t007-input-select-picker-bg: transparent;
125
+ --t007-input-select-picker-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23000' %3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='m19.5 8.25-7.5 7.5-7.5-7.5' /%3E%3C/svg%3E%0A");
126
+ --t007-input-option-color: var(--t007-input-inverse-color);
127
+ --t007-input-option-active-color: var(--t007-input-inverse-color);
128
+ --t007-input-option-bg: rgb(from var(--t007-input-color) r g b / 0.777);
129
+ --t007-input-option-checked-bg: rgb(from var(--t007-input-checkbox-checked-background) r g b / 0.666);
130
+ --t007-input-option-hover-bg: rgb(from var(--t007-input-color) r g b / 0.999);
131
+ --t007-input-option-checked-hover-bg: rgb(from var(--t007-input-checkbox-checked-background) r g b / 0.888);
132
+ --t007-input-option-border: 1px solid var(--t007-input-base-color);
133
+ --t007-input-option-checked-border: 1px solid rgb(from var(--t007-input-checkbox-checked-background) r g b / 0.15);
134
+ --t007-input-option-focus-border: 1px solid var(--t007-input-focused-color);
135
+ --t007-input-option-blur: 3.5px;
136
+ --t007-input-option-entry-scale: 0.25;
137
+ --t007-input-option-stagger-delay: 20ms;
138
+ --t007-input-color-height: var(--t007-input-height);
139
+ --t007-input-color-border: none;
140
+ --t007-input-color-radius: 50%;
120
141
  }
121
142
  :where(:root) {
122
143
  --t007-input-checkmark-color: white;
123
144
  --t007-input-checkmark-width: 2px;
124
145
  --t007-input-checkbox-background: whitesmoke;
125
146
  --t007-input-checkbox-checked-background: dodgerblue;
126
- --t007-input-checkbox-border-color: #707070;
127
- --t007-input-checkbox-checked-border-color: black;
147
+ --t007-input-checkbox-border-color: rgb(from var(--t007-input-color) calc(r + 112) calc(g + 112) calc(b + 112));
148
+ --t007-input-checkbox-checked-border-color: var(--t007-input-inverse-color);
128
149
  --t007-input-checkbox-border-width: 1px;
129
150
  --t007-input-checkbox-border-radius: calc(var(--t007-input-unit) * 0.2);
130
151
  }
131
152
  :where(:root) {
132
153
  --t007-input-radio-color: dodgerblue;
133
154
  --t007-input-radio-background: whitesmoke;
134
- --t007-input-radio-border-color: #707070;
155
+ --t007-input-radio-border-color: rgb(from var(--t007-input-color) calc(r + 112) calc(g + 112) calc(b + 112));
135
156
  --t007-input-radio-checked-border-color: dodgerblue;
136
157
  --t007-input-radio-checked-background: whitesmoke;
137
158
  --t007-input-radio-border-width: 1px;
@@ -388,7 +409,7 @@
388
409
  resize: none;
389
410
  }
390
411
  :where(select.t007-input::picker(select)) {
391
- color: black;
412
+ color: var(--t007-input-inverse-color);
392
413
  }
393
414
  .t007-input::placeholder {
394
415
  color: currentColor;
@@ -403,7 +424,7 @@
403
424
  padding-block: var(--t007-input-sb-active-margin);
404
425
  padding-left: var(--t007-input-sb-active-margin);
405
426
  }
406
- :where(.t007-input[type=file])::file-selector-button {
427
+ :where(.t007-input-bleeding-edge input[type=file])::file-selector-button {
407
428
  font-family: inherit;
408
429
  font-weight: bold;
409
430
  font-size: calc(var(--t007-input-unit) / 1.25);
@@ -419,10 +440,10 @@
419
440
  cursor: pointer;
420
441
  transition: filter 200ms ease;
421
442
  }
422
- :where(.t007-input[type=file])::file-selector-button:where(:active) {
443
+ :where(.t007-input-bleeding-edge input[type=file])::file-selector-button:where(:active) {
423
444
  border-width: 1px;
424
445
  }
425
- :where(.t007-input[type=file])::file-selector-button:where(:hover, :focus-visible) {
446
+ :where(.t007-input-bleeding-edge input[type=file])::file-selector-button:where(:hover, :focus-visible) {
426
447
  filter: brightness(80%);
427
448
  }
428
449
  :where(.t007-input[type=file].t007-input-image-selected)::file-selector-button {
@@ -725,3 +746,118 @@
725
746
  opacity: 0;
726
747
  }
727
748
  }
749
+ .t007-input-bleeding-edge :is(#o, select) {
750
+ white-space: nowrap;
751
+ }
752
+ @supports (appearance: base-select) {
753
+ .t007-input-bleeding-edge :is(#o, select),
754
+ .t007-input-bleeding-edge :is(#o, select)::picker(select) {
755
+ appearance: var(--t007-input-select-appearance);
756
+ }
757
+ .t007-input-bleeding-edge :is(#o, select) {
758
+ position: relative;
759
+ align-items: center;
760
+ }
761
+ .t007-input-bleeding-edge :is(#o, select)::picker-icon {
762
+ content: "";
763
+ position: relative;
764
+ width: var(--t007-input-unit);
765
+ height: var(--t007-input-unit);
766
+ background-image: var(--t007-input-select-picker-icon);
767
+ background-position: center;
768
+ background-repeat: no-repeat;
769
+ transition: all var(--t007-input-select-transition-time) ease-out;
770
+ transition-timing-function: var(--t007-input-select-timing);
771
+ }
772
+ .t007-input-bleeding-edge :is(#o, select):open::picker-icon {
773
+ rotate: 180deg;
774
+ }
775
+ .t007-input-bleeding-edge :is(#o, select):active::picker-icon {
776
+ translate: 0 calc(var(--t007-input-unit) / 10);
777
+ }
778
+ .t007-input-bleeding-edge :is(#o, select)::picker(select) {
779
+ background: var(--t007-input-select-picker-bg);
780
+ margin: calc(var(--t007-input-unit) / 1.34) 2px calc(var(--t007-input-unit) / 1.34) 1px;
781
+ border: none;
782
+ transition-property: display, overlay;
783
+ transition-duration: calc(var(--t007-input-select-transition-time) * 2.5);
784
+ transition-behavior: allow-discrete;
785
+ }
786
+ .t007-input-bleeding-edge :is(#o, select) option {
787
+ position: relative;
788
+ backdrop-filter: blur(var(--t007-input-option-blur));
789
+ border-radius: calc(var(--t007-input-unit) / 4);
790
+ display: flex;
791
+ justify-content: center;
792
+ margin-bottom: calc(var(--t007-input-unit) / 4);
793
+ padding: calc(var(--t007-input-unit) / 3) calc(var(--t007-input-unit) / 2.5);
794
+ background: var(--t007-input-option-bg);
795
+ color: var(--t007-input-option-color);
796
+ border: var(--t007-input-option-border);
797
+ transition-property: opacity, scale;
798
+ transition-duration: var(--t007-input-select-transition-time);
799
+ transition-delay: calc((sibling-count() - sibling-index()) * var(--t007-input-option-stagger-delay));
800
+ scale: var(--t007-input-option-entry-scale);
801
+ opacity: 0;
802
+ }
803
+ .t007-input-bleeding-edge :is(#o, select) option:is(:checked, :focus) {
804
+ color: var(--t007-input-option-active-color);
805
+ }
806
+ .t007-input-bleeding-edge :is(#o, select) option:checked {
807
+ background: var(--t007-input-option-checked-bg);
808
+ border: var(--t007-input-option-checked-border);
809
+ }
810
+ .t007-input-bleeding-edge :is(#o, select) option:focus {
811
+ border: var(--t007-input-option-focus-border);
812
+ }
813
+ .t007-input-bleeding-edge :is(#o, select) option:hover {
814
+ background: var(--t007-input-option-hover-bg);
815
+ }
816
+ .t007-input-bleeding-edge :is(#o, select) option:checked:hover {
817
+ background: var(--t007-input-option-checked-hover-bg);
818
+ }
819
+ .t007-input-bleeding-edge :is(#o, select) option:focus-visible {
820
+ outline: none !important;
821
+ }
822
+ .t007-input-bleeding-edge :is(#o, select) option::checkmark {
823
+ display: none;
824
+ }
825
+ .t007-input-bleeding-edge :is(#o, select):open option {
826
+ scale: 1;
827
+ opacity: 1;
828
+ transition-delay: calc(sibling-index() * var(--t007-input-option-stagger-delay));
829
+ }
830
+ @starting-style {
831
+ .t007-input-bleeding-edge :is(#o, select):open option {
832
+ scale: var(--t007-input-option-entry-scale);
833
+ opacity: 0;
834
+ }
835
+ }
836
+ }
837
+ .t007-input-bleeding-edge:has(input[type=color]) {
838
+ --t007-input-width: var(--t007-input-height);
839
+ --t007-input-padding: 0;
840
+ --t007-input-border-radius: calc(var(--t007-input-height) / 2);
841
+ }
842
+ .t007-input-bleeding-edge:has(input[type=color]) .t007-input-wrapper {
843
+ box-shadow: 0 0 calc(var(--t007-input-unit) / 2.1) var(--input-color);
844
+ }
845
+ .t007-input-bleeding-edge:has(input[type=color]) .t007-input-outline-notch {
846
+ max-width: 0;
847
+ }
848
+ .t007-input-bleeding-edge input[type=color] {
849
+ width: var(--t007-input-height);
850
+ height: var(--t007-input-height);
851
+ padding: 0;
852
+ }
853
+ .t007-input-bleeding-edge input[type=color]::-webkit-color-swatch-wrapper {
854
+ padding: 0;
855
+ }
856
+ .t007-input-bleeding-edge input[type=color]::-webkit-color-swatch {
857
+ border: var(--t007-input-color-border);
858
+ border-radius: var(--t007-input-color-radius);
859
+ }
860
+ .t007-input-bleeding-edge input[type=color]::-moz-color-swatch {
861
+ border: var(--t007-input-color-border);
862
+ border-radius: var(--t007-input-color-radius);
863
+ }
package/dist/index.d.ts CHANGED
@@ -54,20 +54,20 @@ export interface FormManager {
54
54
  /** Attach a fallback helper node.
55
55
  * @param field Field wrapper element.
56
56
  */
57
- setFallbackHelper(field: HTMLElement): void;
57
+ setFallbackHelper(field: HTMLDivElement): void;
58
58
  /** Wire listeners onto a managed field.
59
59
  * @param field Field wrapper element.
60
60
  */
61
- setFieldListeners(field: HTMLElement): void;
61
+ setFieldListeners(field: HTMLDivElement): void;
62
62
  /** Normalize field markup before use.
63
63
  * @param field Field wrapper element.
64
64
  */
65
- setUpField(field: HTMLElement): void;
65
+ setUpField(field: HTMLDivElement): void;
66
66
  /** Create a field element from options.
67
67
  * @param options Field configuration.
68
68
  * @returns Created field element.
69
69
  */
70
- field(options: FieldOptions): HTMLElement;
70
+ field(options: FieldOptions): HTMLDivElement;
71
71
  /** Validate a form and attach the proper hooks.
72
72
  * @param form Form element to validate.
73
73
  */
@@ -82,11 +82,11 @@ export const formManager: FormManager;
82
82
  * @param options Field configuration.
83
83
  * @returns Created field element.
84
84
  */
85
- export const field = FormManager["field"];
85
+ export const field: FormManager["field"];
86
86
  /** Attach validation hooks to a form element.
87
87
  * @param form Form element to validate.
88
88
  */
89
- export const handleFormValidation = FormManager["handleFormValidation"];
89
+ export const handleFormValidation: FormManager["handleFormValidation"];
90
90
 
91
91
  declare global {
92
92
  interface T007Namespace {
@@ -17,7 +17,7 @@
17
17
  }
18
18
  }
19
19
 
20
- // ../../../sia-reactor/dist/chunk-EZ4VRGYI.js
20
+ // ../../../sia-reactor/dist/chunk-4PLMBUCP.js
21
21
  var CTX = {
22
22
  /** Flag indicating whether the application is running in development mode. */
23
23
  isDevEnv: "undefined" !== typeof process ? process.env.NODE_ENV !== "production" : true,
@@ -30,7 +30,7 @@
30
30
  var RTR_LOG = console.log.bind(console, "[S.I.A Reactor]");
31
31
  var NIL = Object.freeze({});
32
32
 
33
- // ../utils/dist/chunk-Y5YJMRXD.js
33
+ // ../utils/dist/chunk-4O76EZJ4.js
34
34
  var INTERACTIVE_SELECTOR = ":is(button,[href],input:not([type='hidden']),select,textarea,details>summary,[contenteditable='true'],iframe,audio[controls],video[controls],[tabindex]):not([disabled],[tabindex='-1'],[data-focus-guard],[inert],[inert] *)";
35
35
  var VIRTUAL_RESOURCE = /* @__PURE__ */ Symbol.for("T007_VIRTUAL_RESOURCE");
36
36
  function loadResource(req, type = "style", { module, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, attempts = 3, retryKey = false } = {}, w = window) {
@@ -69,15 +69,18 @@
69
69
  function isArr(obj) {
70
70
  return Array.isArray(obj);
71
71
  }
72
- function isSameURL(src1, src2) {
73
- if (!isStr(src1) || !isStr(src2) || !src1 || !src2) return false;
72
+ function cleanURL(url) {
74
73
  try {
75
- const u1 = new URL(src1, window.location.href), u2 = new URL(src2, window.location.href);
76
- return decodeURIComponent(u1.origin + u1.pathname) === decodeURIComponent(u2.origin + u2.pathname);
74
+ const u = new URL(url, window.location.href);
75
+ return decodeURIComponent(u.origin + u.pathname);
77
76
  } catch {
78
- return src1.replace(/\\/g, "/").split("?")[0].trim() === src2.replace(/\\/g, "/").split("?")[0].trim();
77
+ return url.replace(/\\/g, "/").split("?")[0].trim();
79
78
  }
80
79
  }
80
+ function isSameURL(url1, url2) {
81
+ if (!isStr(url1) || !isStr(url2) || !url1 || !url2) return false;
82
+ return cleanURL(url1) === cleanURL(url2);
83
+ }
81
84
  function formatSize(bytes, decimals = 3, base = 1e3) {
82
85
  if (bytes < base) return `${bytes} byte${bytes == 1 ? "" : "s"}`;
83
86
  const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(base)), units.length - 1);
@@ -226,7 +229,9 @@
226
229
  getFilesHelper: (files, opts) => getFilesHelper(files, opts),
227
230
  formatSize: (size, decimals = 3, base = 1e3) => formatSize(size, decimals, base),
228
231
  togglePasswordType: (input) => input.type = input.type === "password" ? "text" : "password",
229
- toggleFilled: (input) => input?.toggleAttribute("data-filled", input.type === "checkbox" || input.type === "radio" ? input.checked : input.value !== "" || input.files?.length > 0),
232
+ toggleFilled(input) {
233
+ input.toggleAttribute("data-filled", input.type === "checkbox" || input.type === "radio" ? input.checked : input.value !== "" || input.files?.length > 0), input.type === "color" && input.t007Field.style.setProperty("--input-color", input.value);
234
+ },
230
235
  setFallbackHelper(field2) {
231
236
  const helperTextWrapper = field2?.querySelector(".t007-input-helper-text-wrapper");
232
237
  !helperTextWrapper?.querySelector(".t007-input-helper-text[data-violation='auto']") && helperTextWrapper?.append(createEl("p", { className: "t007-input-helper-text" }, { violation: "auto" }));
@@ -260,12 +265,13 @@
260
265
  initScrollAssist(field2.querySelector(".t007-input-helper-text-wrapper"), { vertical: false });
261
266
  },
262
267
  setUpField(field2) {
263
- if (field2.dataset.setUp) return;
264
- t007.FM.toggleFilled(field2.querySelector(".t007-input")), t007.FM.setFallbackHelper(field2), t007.FM.setFieldListeners(field2);
265
- field2.dataset.setUp = "true";
268
+ if (field2.dataset.setup) return;
269
+ const input = field2.querySelector(".t007-input");
270
+ t007.FM.toggleFilled((input.t007Field = field2, input)), t007.FM.setFallbackHelper(field2), t007.FM.setFieldListeners(field2);
271
+ field2.dataset.setup = "true";
266
272
  },
267
- field({ isWrapper = false, label = "", type = "text", placeholder = "", custom = "", minSize, maxSize, minTotalSize, maxTotalSize, options = [], indeterminate = false, eyeToggler = true, passwordMeter = true, helperText = {}, className = "", fieldClassName = "", children, startIcon = "", endIcon = "", nativeIcon = "", passwordVisibleIcon = "", passwordHiddenIcon = "", ...otherProps }) {
268
- const isSelect = type === "select", isTextArea = type === "textarea", isCheckboxOrRadio = type === "checkbox" || type === "radio", field2 = createEl("div", { className: `t007-input-field${isWrapper ? " t007-input-is-wrapper" : ""}${indeterminate ? " t007-input-indeterminate" : ""}${!!nativeIcon ? " t007-input-icon-override" : ""}${helperText === false ? " t007-input-no-helper" : ""}${fieldClassName ? ` ${fieldClassName}` : ""}` }), labelEl = createEl("label", { className: isCheckboxOrRadio ? `t007-input-${type}-wrapper` : "t007-input-wrapper" });
273
+ field({ isWrapper = false, label = "", type = "text", placeholder = "", custom = "", minSize, maxSize, minTotalSize, maxTotalSize, options = [], indeterminate = false, eyeToggler = true, passwordMeter = true, helperText = {}, className = "", fieldClassName = "", children, startIcon = "", endIcon = "", nativeIcon = "", passwordVisibleIcon = "", passwordHiddenIcon = "", bleedingEdge = true, ...otherProps }) {
274
+ const isSelect = type === "select", isTextArea = type === "textarea", isCheckboxOrRadio = type === "checkbox" || type === "radio", field2 = createEl("div", { className: `t007-input-field${isWrapper ? " t007-input-is-wrapper" : ""}${indeterminate ? " t007-input-indeterminate" : ""}${!!nativeIcon ? " t007-input-icon-override" : ""}${helperText === false ? " t007-input-no-helper" : ""}${fieldClassName ? ` ${fieldClassName}` : ""}${bleedingEdge ? " t007-input-bleeding-edge" : ""}` }), labelEl = createEl("label", { className: isCheckboxOrRadio ? `t007-input-${type}-wrapper` : "t007-input-wrapper" });
269
275
  field2.append(labelEl);
270
276
  if (isCheckboxOrRadio) {
271
277
  labelEl.innerHTML = `
@@ -344,7 +350,7 @@
344
350
  form.classList.toggle("t007-input-submit-loading", false);
345
351
  });
346
352
  function toggleError(input, bool, flag = false) {
347
- const field2 = input.closest(".t007-input-field"), floatingLabel = field2.querySelector(".t007-input-floating-label");
353
+ const field2 = input.t007Field, floatingLabel = field2.querySelector(".t007-input-floating-label");
348
354
  if (bool && flag) {
349
355
  input.setAttribute("data-error", "");
350
356
  floatingLabel?.classList.add("t007-input-shake"), setTimeout(() => floatingLabel?.classList.remove("t007-input-shake"), 520);
@@ -352,17 +358,17 @@
352
358
  toggleHelper(input, input.hasAttribute("data-error"));
353
359
  }
354
360
  function toggleHelper(input, bool) {
355
- const field2 = input.closest(".t007-input-field"), violation = t007.FM.violationKeys.find((violation2) => input.Validity?.[violation2] || input.validity[violation2]) ?? "", helper = field2.querySelector(`.t007-input-helper-text[data-violation="${violation}"]`), fallbackHelper = field2.querySelector(`.t007-input-helper-text[data-violation="auto"]`);
356
- input.closest(".t007-input-field").querySelectorAll(`.t007-input-helper-text:not([data-violation="${violation}"])`).forEach((helper2) => helper2?.classList.remove("t007-input-show"));
361
+ const field2 = input.t007Field, violation = t007.FM.violationKeys.find((violation2) => input.Validity?.[violation2] || input.validity[violation2]) ?? "", helper = field2.querySelector(`.t007-input-helper-text[data-violation="${violation}"]`), fallbackHelper = field2.querySelector(`.t007-input-helper-text[data-violation="auto"]`);
362
+ input.t007Field.querySelectorAll(`.t007-input-helper-text:not([data-violation="${violation}"])`).forEach((helper2) => helper2?.classList.remove("t007-input-show"));
357
363
  if (helper) helper.classList.toggle("t007-input-show", bool);
358
364
  else if (fallbackHelper) fallbackHelper.textContent = input.validationMessage, fallbackHelper.classList.toggle("t007-input-show", bool);
359
365
  }
360
366
  function updatePasswordMeter(input) {
361
- const passwordMeter = input.closest(".t007-input-field").querySelector(".t007-input-password-meter");
367
+ const passwordMeter = input.t007Field.querySelector(".t007-input-password-meter");
362
368
  if (passwordMeter) passwordMeter.dataset.strengthLevel = `${getStrengthLevel(input.value, Number(input.minLength ?? 0))}`;
363
369
  }
364
370
  function validateInput(input, flag = false) {
365
- if (form.dataset.globalError || !input?.classList.contains("t007-input")) return;
371
+ if (form.dataset.globalError || !input.classList.contains("t007-input")) return;
366
372
  updatePasswordMeter(input);
367
373
  let value, errorBool;
368
374
  switch (input.custom ?? input.getAttribute("custom")) {
package/dist/index.js CHANGED
@@ -65,7 +65,9 @@ var formManager = {
65
65
  getFilesHelper: (files, opts) => getFilesHelper(files, opts),
66
66
  formatSize: (size, decimals = 3, base = 1e3) => formatFileSize(size, decimals, base),
67
67
  togglePasswordType: (input) => input.type = input.type === "password" ? "text" : "password",
68
- toggleFilled: (input) => input?.toggleAttribute("data-filled", input.type === "checkbox" || input.type === "radio" ? input.checked : input.value !== "" || input.files?.length > 0),
68
+ toggleFilled(input) {
69
+ input.toggleAttribute("data-filled", input.type === "checkbox" || input.type === "radio" ? input.checked : input.value !== "" || input.files?.length > 0), input.type === "color" && input.t007Field.style.setProperty("--input-color", input.value);
70
+ },
69
71
  setFallbackHelper(field2) {
70
72
  const helperTextWrapper = field2?.querySelector(".t007-input-helper-text-wrapper");
71
73
  !helperTextWrapper?.querySelector(".t007-input-helper-text[data-violation='auto']") && helperTextWrapper?.append(createEl("p", { className: "t007-input-helper-text" }, { violation: "auto" }));
@@ -99,12 +101,13 @@ var formManager = {
99
101
  initScrollAssist(field2.querySelector(".t007-input-helper-text-wrapper"), { vertical: false });
100
102
  },
101
103
  setUpField(field2) {
102
- if (field2.dataset.setUp) return;
103
- t007.FM.toggleFilled(field2.querySelector(".t007-input")), t007.FM.setFallbackHelper(field2), t007.FM.setFieldListeners(field2);
104
- field2.dataset.setUp = "true";
104
+ if (field2.dataset.setup) return;
105
+ const input = field2.querySelector(".t007-input");
106
+ t007.FM.toggleFilled((input.t007Field = field2, input)), t007.FM.setFallbackHelper(field2), t007.FM.setFieldListeners(field2);
107
+ field2.dataset.setup = "true";
105
108
  },
106
- field({ isWrapper = false, label = "", type = "text", placeholder = "", custom = "", minSize, maxSize, minTotalSize, maxTotalSize, options = [], indeterminate = false, eyeToggler = true, passwordMeter = true, helperText = {}, className = "", fieldClassName = "", children, startIcon = "", endIcon = "", nativeIcon = "", passwordVisibleIcon = "", passwordHiddenIcon = "", ...otherProps }) {
107
- const isSelect = type === "select", isTextArea = type === "textarea", isCheckboxOrRadio = type === "checkbox" || type === "radio", field2 = createEl("div", { className: `t007-input-field${isWrapper ? " t007-input-is-wrapper" : ""}${indeterminate ? " t007-input-indeterminate" : ""}${!!nativeIcon ? " t007-input-icon-override" : ""}${helperText === false ? " t007-input-no-helper" : ""}${fieldClassName ? ` ${fieldClassName}` : ""}` }), labelEl = createEl("label", { className: isCheckboxOrRadio ? `t007-input-${type}-wrapper` : "t007-input-wrapper" });
109
+ field({ isWrapper = false, label = "", type = "text", placeholder = "", custom = "", minSize, maxSize, minTotalSize, maxTotalSize, options = [], indeterminate = false, eyeToggler = true, passwordMeter = true, helperText = {}, className = "", fieldClassName = "", children, startIcon = "", endIcon = "", nativeIcon = "", passwordVisibleIcon = "", passwordHiddenIcon = "", bleedingEdge = true, ...otherProps }) {
110
+ const isSelect = type === "select", isTextArea = type === "textarea", isCheckboxOrRadio = type === "checkbox" || type === "radio", field2 = createEl("div", { className: `t007-input-field${isWrapper ? " t007-input-is-wrapper" : ""}${indeterminate ? " t007-input-indeterminate" : ""}${!!nativeIcon ? " t007-input-icon-override" : ""}${helperText === false ? " t007-input-no-helper" : ""}${fieldClassName ? ` ${fieldClassName}` : ""}${bleedingEdge ? " t007-input-bleeding-edge" : ""}` }), labelEl = createEl("label", { className: isCheckboxOrRadio ? `t007-input-${type}-wrapper` : "t007-input-wrapper" });
108
111
  field2.append(labelEl);
109
112
  if (isCheckboxOrRadio) {
110
113
  labelEl.innerHTML = `
@@ -183,7 +186,7 @@ var formManager = {
183
186
  form.classList.toggle("t007-input-submit-loading", false);
184
187
  });
185
188
  function toggleError(input, bool, flag = false) {
186
- const field2 = input.closest(".t007-input-field"), floatingLabel = field2.querySelector(".t007-input-floating-label");
189
+ const field2 = input.t007Field, floatingLabel = field2.querySelector(".t007-input-floating-label");
187
190
  if (bool && flag) {
188
191
  input.setAttribute("data-error", "");
189
192
  floatingLabel?.classList.add("t007-input-shake"), setTimeout(() => floatingLabel?.classList.remove("t007-input-shake"), 520);
@@ -191,17 +194,17 @@ var formManager = {
191
194
  toggleHelper(input, input.hasAttribute("data-error"));
192
195
  }
193
196
  function toggleHelper(input, bool) {
194
- const field2 = input.closest(".t007-input-field"), violation = t007.FM.violationKeys.find((violation2) => input.Validity?.[violation2] || input.validity[violation2]) ?? "", helper = field2.querySelector(`.t007-input-helper-text[data-violation="${violation}"]`), fallbackHelper = field2.querySelector(`.t007-input-helper-text[data-violation="auto"]`);
195
- input.closest(".t007-input-field").querySelectorAll(`.t007-input-helper-text:not([data-violation="${violation}"])`).forEach((helper2) => helper2?.classList.remove("t007-input-show"));
197
+ const field2 = input.t007Field, violation = t007.FM.violationKeys.find((violation2) => input.Validity?.[violation2] || input.validity[violation2]) ?? "", helper = field2.querySelector(`.t007-input-helper-text[data-violation="${violation}"]`), fallbackHelper = field2.querySelector(`.t007-input-helper-text[data-violation="auto"]`);
198
+ input.t007Field.querySelectorAll(`.t007-input-helper-text:not([data-violation="${violation}"])`).forEach((helper2) => helper2?.classList.remove("t007-input-show"));
196
199
  if (helper) helper.classList.toggle("t007-input-show", bool);
197
200
  else if (fallbackHelper) fallbackHelper.textContent = input.validationMessage, fallbackHelper.classList.toggle("t007-input-show", bool);
198
201
  }
199
202
  function updatePasswordMeter(input) {
200
- const passwordMeter = input.closest(".t007-input-field").querySelector(".t007-input-password-meter");
203
+ const passwordMeter = input.t007Field.querySelector(".t007-input-password-meter");
201
204
  if (passwordMeter) passwordMeter.dataset.strengthLevel = `${getStrengthLevel(input.value, Number(input.minLength ?? 0))}`;
202
205
  }
203
206
  function validateInput(input, flag = false) {
204
- if (form.dataset.globalError || !input?.classList.contains("t007-input")) return;
207
+ if (form.dataset.globalError || !input.classList.contains("t007-input")) return;
205
208
  updatePasswordMeter(input);
206
209
  let value, errorBool;
207
210
  switch (input.custom ?? input.getAttribute("custom")) {
package/dist/react.d.ts CHANGED
@@ -48,6 +48,8 @@ interface BaseProps {
48
48
  /** End icon rendered inside the field control. */
49
49
  endIcon?: React.ReactNode;
50
50
  // onFlagError?: (args: { violation: keyof ValidityState | null; helper: string }) => void;
51
+ /** Whether to activate bleeding edge CSS styles that augment native styles for input types, e.g. file, color, select, e.t.c */
52
+ bleedingEdge?: boolean;
51
53
  }
52
54
  type PasswordInputProps = BaseProps & InputAttributes & PasswordInputAddon;
53
55
  type FileInputProps = BaseProps & InputAttributes & FileInputAddon;
package/dist/react.js CHANGED
@@ -63,7 +63,7 @@ var isNativeIconType = (t) => nativeIconTypes.includes(t);
63
63
  import { useScrollAssist } from "@t007/utils/hooks/react";
64
64
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
65
65
  var Input = React.forwardRef(function Input2(props, ref) {
66
- const { isWrapper = false, label = "", type = "text", helperText, error, custom = "", className, fieldClassName, children, endIcon, ...otherProps } = props;
66
+ const { isWrapper = false, label = "", type = "text", helperText, error, custom = "", className = "", fieldClassName = "", children, endIcon, bleedingEdge = true, ...otherProps } = props;
67
67
  let options;
68
68
  let indeterminate = false;
69
69
  let minLength;
@@ -147,7 +147,7 @@ var Input = React.forwardRef(function Input2(props, ref) {
147
147
  const el = inputRef.current;
148
148
  if (!el) return;
149
149
  const form = el.closest("form");
150
- setFilled(hasValue(el));
150
+ setFilled(hasValue(el)), el.type === "color" && el.closest(".t007-input-field")?.style.setProperty("--input-color", el.value);
151
151
  updatePasswordStrength(el.value);
152
152
  if (custom === "confirm_password") {
153
153
  const passwordInput = form?.querySelector("[custom='password']");
@@ -156,7 +156,7 @@ var Input = React.forwardRef(function Input2(props, ref) {
156
156
  const confirmInput = form?.querySelector("[custom='confirm_password']");
157
157
  if (confirmInput) confirmInput.setCustomValidity(el.value.trim() === confirmInput.value.trim() ? "" : "Both passwords do not match");
158
158
  }
159
- if (el.type === "radio") el?.closest("form")?.querySelectorAll(".t007-input[name='radio']").forEach(fireInput);
159
+ if (el.type === "radio") form?.querySelectorAll(".t007-input[name='radio']").forEach(fireInput);
160
160
  validateInput(el);
161
161
  }, [custom, hasValue, updatePasswordStrength, validateInput]);
162
162
  useEffect(() => void fireInput(inputRef.current), []);
@@ -164,7 +164,7 @@ var Input = React.forwardRef(function Input2(props, ref) {
164
164
  useScrollAssist(helperTextWrapperRef, { pxPerSecond: 80 });
165
165
  useImperativeHandle(ref, () => inputRef.current);
166
166
  const Wrapper = isWrapper ? "div" : "label";
167
- return /* @__PURE__ */ jsxs("div", { className: `t007-input-field ${fieldClassName}${isWrapper ? " t007-input-is-wrapper" : ""}${indeterminate ? " t007-input-indeterminate" : ""}${nativeIcon ? " t007-input-icon-override" : ""}${helperText === false ? " t007-input-no-helper" : ""}`, children: [
167
+ return /* @__PURE__ */ jsxs("div", { className: `t007-input-field ${fieldClassName}${isWrapper ? " t007-input-is-wrapper" : ""}${indeterminate ? " t007-input-indeterminate" : ""}${nativeIcon ? " t007-input-icon-override" : ""}${helperText === false ? " t007-input-no-helper" : ""}${bleedingEdge ? " t007-input-bleeding-edge" : ""}`, children: [
168
168
  /* @__PURE__ */ jsxs(Wrapper, { className: type === "checkbox" || type === "radio" ? `t007-input-${type}-wrapper` : "t007-input-wrapper", children: [
169
169
  type === "checkbox" || type === "radio" ? /* @__PURE__ */ jsxs(Fragment, { children: [
170
170
  /* @__PURE__ */ jsx("span", { className: `t007-input-${type}-box`, children: /* @__PURE__ */ jsx("span", { className: `t007-input-${type}-tag` }) }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t007/input",
3
- "version": "0.0.29",
3
+ "version": "0.0.31",
4
4
  "description": "A lightweight, pure JS input system.",
5
5
  "author": "Oketade Oluwatobiloba <tobioketade007@gmail.com>",
6
6
  "license": "MIT",
@@ -68,7 +68,7 @@
68
68
  "react-dom": "^18.3.1"
69
69
  },
70
70
  "dependencies": {
71
- "@t007/utils": "^0.0.31"
71
+ "@t007/utils": "^0.0.33"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "react": "^18.0.0"