@ews-admin/global-design-system 1.1.6 → 1.1.7

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 (45) hide show
  1. package/dist/components/Logo/Logo.d.ts +1 -1
  2. package/dist/components/Logo/Logo.d.ts.map +1 -1
  3. package/dist/components/MultiSearchAutocomplete/MultiSearchAutocomplete.d.ts +1 -1
  4. package/dist/components/MultiSearchAutocomplete/MultiSearchAutocomplete.d.ts.map +1 -1
  5. package/dist/components/Select/Select.d.ts +91 -0
  6. package/dist/components/Select/Select.d.ts.map +1 -0
  7. package/dist/components/Select/index.d.ts +3 -0
  8. package/dist/components/Select/index.d.ts.map +1 -0
  9. package/dist/components/ThemeDebugger/ThemeDebugger.d.ts +6 -0
  10. package/dist/components/ThemeDebugger/ThemeDebugger.d.ts.map +1 -0
  11. package/dist/components/ThemeDebugger/index.d.ts +3 -0
  12. package/dist/components/ThemeDebugger/index.d.ts.map +1 -0
  13. package/dist/hooks/index.d.ts +2 -0
  14. package/dist/hooks/index.d.ts.map +1 -1
  15. package/dist/hooks/useSelectField.d.ts +16 -0
  16. package/dist/hooks/useSelectField.d.ts.map +1 -0
  17. package/dist/icons/ArrowRightIcon.d.ts +4 -0
  18. package/dist/icons/ArrowRightIcon.d.ts.map +1 -0
  19. package/dist/icons/CheckIcon.d.ts +4 -0
  20. package/dist/icons/CheckIcon.d.ts.map +1 -0
  21. package/dist/icons/EyeIcon.d.ts +4 -0
  22. package/dist/icons/EyeIcon.d.ts.map +1 -0
  23. package/dist/icons/EyeOffIcon.d.ts +4 -0
  24. package/dist/icons/EyeOffIcon.d.ts.map +1 -0
  25. package/dist/icons/SearchIcon.d.ts +4 -0
  26. package/dist/icons/SearchIcon.d.ts.map +1 -0
  27. package/dist/index.css +2 -2
  28. package/dist/index.d.ts +114 -4
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.esm.css +2 -2
  31. package/dist/index.esm.js +761 -8
  32. package/dist/index.esm.js.map +1 -1
  33. package/dist/index.js +762 -6
  34. package/dist/index.js.map +1 -1
  35. package/package.json +7 -6
  36. package/src/components/Logo/Logo.tsx +1 -1
  37. package/src/components/MultiSearchAutocomplete/MultiSearchAutocomplete.tsx +1 -1
  38. package/src/components/Select/Select.tsx +553 -0
  39. package/src/components/Select/index.ts +2 -0
  40. package/src/components/ThemeDebugger/ThemeDebugger.tsx +101 -0
  41. package/src/components/ThemeDebugger/index.ts +2 -0
  42. package/src/hooks/index.ts +2 -0
  43. package/src/hooks/useSelectField.ts +53 -0
  44. package/src/index.ts +8 -1
  45. package/src/styles/index.css +49 -0
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import React, { forwardRef, createElement, useState, useEffect, useRef, useCallback, createContext, useContext } from 'react';
2
+ import React, { forwardRef, createElement, useState, useId, useRef, useEffect, useCallback, createContext, useContext } from 'react';
3
3
 
4
4
  function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
5
5
 
@@ -205,11 +205,11 @@ const createLucideIcon = (iconName, iconNode) => {
205
205
  */
206
206
 
207
207
 
208
- const __iconNode$b = [
208
+ const __iconNode$c = [
209
209
  ["path", { d: "M5 12h14", key: "1ays0h" }],
210
210
  ["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
211
211
  ];
212
- const ArrowRight = createLucideIcon("arrow-right", __iconNode$b);
212
+ const ArrowRight = createLucideIcon("arrow-right", __iconNode$c);
213
213
 
214
214
  /**
215
215
  * @license lucide-react v0.544.0 - ISC
@@ -219,8 +219,19 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$b);
219
219
  */
220
220
 
221
221
 
222
- const __iconNode$a = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
223
- const Check = createLucideIcon("check", __iconNode$a);
222
+ const __iconNode$b = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
223
+ const Check = createLucideIcon("check", __iconNode$b);
224
+
225
+ /**
226
+ * @license lucide-react v0.544.0 - ISC
227
+ *
228
+ * This source code is licensed under the ISC license.
229
+ * See the LICENSE file in the root directory of this source tree.
230
+ */
231
+
232
+
233
+ const __iconNode$a = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
234
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$a);
224
235
 
225
236
  /**
226
237
  * @license lucide-react v0.544.0 - ISC
@@ -451,6 +462,233 @@ const Input = React.forwardRef(({ className, variant = "default", size = "md", l
451
462
  });
452
463
  Input.displayName = "Input";
453
464
 
465
+ const Select = forwardRef(({ options = [], value, onChange, placeholder = "Select an option...", label, helperText, error, isError = false, size = "md", disabled = false, required = false, searchable = false, multiple: _multiple = false, selectClassName, containerClassName, dropdownClassName, maxHeight = 200, clearable = false, renderOption, renderValue, ...props }, ref) => {
466
+ const generatedId = useId();
467
+ const selectId = `select-${generatedId}`;
468
+ const hasError = isError || !!error;
469
+ const [isOpen, setIsOpen] = useState(false);
470
+ const [searchTerm, setSearchTerm] = useState("");
471
+ const [focusedIndex, setFocusedIndex] = useState(-1);
472
+ const [dropdownPosition, setDropdownPosition] = useState("bottom");
473
+ const containerRef = useRef(null);
474
+ const inputRef = useRef(null);
475
+ const dropdownRef = useRef(null);
476
+ const optionRefs = useRef([]);
477
+ // Find selected option
478
+ const selectedOption = options.find((option) => option.value === value);
479
+ // Filter options based on search term
480
+ const filteredOptions = searchable
481
+ ? options.filter((option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()))
482
+ : options;
483
+ // Calculate dropdown position based on available space
484
+ const calculateDropdownPosition = () => {
485
+ if (!containerRef.current)
486
+ return;
487
+ const containerRect = containerRef.current.getBoundingClientRect();
488
+ const viewportHeight = window.innerHeight;
489
+ // More accurate height calculation
490
+ const optionHeight = 40; // Approximate height per option
491
+ const searchHeight = searchable ? 60 : 0;
492
+ const padding = 16; // py-1 = 8px top + 8px bottom
493
+ const dropdownHeight = Math.min(maxHeight, filteredOptions.length * optionHeight + searchHeight + padding);
494
+ const spaceBelow = viewportHeight - containerRect.bottom;
495
+ const spaceAbove = containerRect.top;
496
+ // Add some buffer (20px) to prevent edge cases
497
+ const buffer = 20;
498
+ console.log("Position calculation:", {
499
+ spaceBelow,
500
+ spaceAbove,
501
+ dropdownHeight,
502
+ viewportHeight,
503
+ containerBottom: containerRect.bottom,
504
+ shouldOpenTop: spaceBelow < dropdownHeight + buffer &&
505
+ spaceAbove > dropdownHeight + buffer,
506
+ });
507
+ // If there's not enough space below but enough space above, position on top
508
+ if (spaceBelow < dropdownHeight + buffer &&
509
+ spaceAbove > dropdownHeight + buffer) {
510
+ setDropdownPosition("top");
511
+ }
512
+ else {
513
+ setDropdownPosition("bottom");
514
+ }
515
+ };
516
+ // Alternative calculation using actual dropdown element when available
517
+ const calculateDropdownPositionWithElement = () => {
518
+ if (!containerRef.current || !dropdownRef.current)
519
+ return;
520
+ const containerRect = containerRef.current.getBoundingClientRect();
521
+ const dropdownRect = dropdownRef.current.getBoundingClientRect();
522
+ const viewportHeight = window.innerHeight;
523
+ const spaceBelow = viewportHeight - containerRect.bottom;
524
+ const spaceAbove = containerRect.top;
525
+ const actualDropdownHeight = dropdownRect.height;
526
+ console.log("Position calculation with element:", {
527
+ spaceBelow,
528
+ spaceAbove,
529
+ actualDropdownHeight,
530
+ viewportHeight,
531
+ containerBottom: containerRect.bottom,
532
+ });
533
+ // If there's not enough space below but enough space above, position on top
534
+ if (spaceBelow < actualDropdownHeight &&
535
+ spaceAbove > actualDropdownHeight) {
536
+ setDropdownPosition("top");
537
+ }
538
+ else {
539
+ setDropdownPosition("bottom");
540
+ }
541
+ };
542
+ // Handle click outside
543
+ useEffect(() => {
544
+ const handleClickOutside = (event) => {
545
+ if (containerRef.current &&
546
+ !containerRef.current.contains(event.target)) {
547
+ setIsOpen(false);
548
+ setSearchTerm("");
549
+ setFocusedIndex(-1);
550
+ }
551
+ };
552
+ document.addEventListener("mousedown", handleClickOutside);
553
+ return () => document.removeEventListener("mousedown", handleClickOutside);
554
+ }, []);
555
+ // Calculate position when dropdown opens
556
+ useEffect(() => {
557
+ if (isOpen) {
558
+ // First calculation based on estimated height
559
+ calculateDropdownPosition();
560
+ // Second calculation after dropdown is rendered with actual height
561
+ requestAnimationFrame(() => {
562
+ calculateDropdownPositionWithElement();
563
+ });
564
+ }
565
+ }, [isOpen, filteredOptions.length, searchable, maxHeight]);
566
+ // Recalculate position on window resize
567
+ useEffect(() => {
568
+ const handleResize = () => {
569
+ if (isOpen) {
570
+ calculateDropdownPosition();
571
+ }
572
+ };
573
+ window.addEventListener("resize", handleResize);
574
+ window.addEventListener("scroll", handleResize);
575
+ return () => {
576
+ window.removeEventListener("resize", handleResize);
577
+ window.removeEventListener("scroll", handleResize);
578
+ };
579
+ }, [isOpen]);
580
+ // Handle keyboard navigation
581
+ const handleKeyDown = (event) => {
582
+ if (disabled)
583
+ return;
584
+ switch (event.key) {
585
+ case "ArrowDown":
586
+ event.preventDefault();
587
+ if (!isOpen) {
588
+ setIsOpen(true);
589
+ }
590
+ else {
591
+ setFocusedIndex((prev) => prev < filteredOptions.length - 1 ? prev + 1 : 0);
592
+ }
593
+ break;
594
+ case "ArrowUp":
595
+ event.preventDefault();
596
+ if (!isOpen) {
597
+ setIsOpen(true);
598
+ }
599
+ else {
600
+ setFocusedIndex((prev) => prev > 0 ? prev - 1 : filteredOptions.length - 1);
601
+ }
602
+ break;
603
+ case "Enter":
604
+ event.preventDefault();
605
+ if (isOpen &&
606
+ focusedIndex >= 0 &&
607
+ focusedIndex < filteredOptions.length) {
608
+ handleSelect(filteredOptions[focusedIndex]);
609
+ }
610
+ else if (!isOpen) {
611
+ setIsOpen(true);
612
+ }
613
+ break;
614
+ case "Escape":
615
+ event.preventDefault();
616
+ setIsOpen(false);
617
+ setSearchTerm("");
618
+ setFocusedIndex(-1);
619
+ break;
620
+ case "Tab":
621
+ setIsOpen(false);
622
+ setSearchTerm("");
623
+ setFocusedIndex(-1);
624
+ break;
625
+ }
626
+ };
627
+ // Handle option selection
628
+ const handleSelect = (option) => {
629
+ if (option.disabled)
630
+ return;
631
+ onChange?.(option.value, option);
632
+ setIsOpen(false);
633
+ setSearchTerm("");
634
+ setFocusedIndex(-1);
635
+ };
636
+ // Handle clear
637
+ const handleClear = (event) => {
638
+ event.stopPropagation();
639
+ onChange?.(undefined, {});
640
+ };
641
+ // Handle toggle
642
+ const handleToggle = () => {
643
+ if (disabled)
644
+ return;
645
+ setIsOpen(!isOpen);
646
+ if (!isOpen && searchable) {
647
+ setTimeout(() => inputRef.current?.focus(), 0);
648
+ }
649
+ };
650
+ // Scroll focused option into view
651
+ useEffect(() => {
652
+ if (focusedIndex >= 0 && optionRefs.current[focusedIndex]) {
653
+ optionRefs.current[focusedIndex]?.scrollIntoView({
654
+ block: "nearest",
655
+ });
656
+ }
657
+ }, [focusedIndex]);
658
+ const sizeClasses = {
659
+ sm: "text-sm px-3 py-1.5",
660
+ md: "text-sm px-3 py-2",
661
+ lg: "text-base px-4 py-2.5",
662
+ };
663
+ const iconSizeClasses = {
664
+ sm: "w-4 h-4",
665
+ md: "w-4 h-4",
666
+ lg: "w-5 h-5",
667
+ };
668
+ return (jsxs("div", { className: cn("w-full", containerClassName), ref: containerRef, children: [label && (jsxs("label", { htmlFor: selectId, className: cn("block text-sm font-medium mb-1", hasError ? "text-ews-error" : "text-ews-gray-700", disabled && "text-ews-gray-400"), children: [label, required && jsx("span", { className: "ml-1 text-ews-error", children: "*" })] })), jsxs("div", { className: "relative", children: [jsx("div", { ref: ref, role: "combobox", "aria-expanded": isOpen, "aria-haspopup": "listbox", "aria-labelledby": label ? selectId : undefined, tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown, onClick: handleToggle, className: cn(
669
+ // Base styles
670
+ "ews-select-trigger w-full bg-white border rounded-md shadow-sm transition-colors cursor-pointer", "focus:outline-none focus:ring-2 focus:ring-offset-0", "disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-ews-gray-50",
671
+ // Size
672
+ sizeClasses[size],
673
+ // Border and focus states
674
+ hasError
675
+ ? "border-ews-error focus:border-ews-error focus:ring-ews-error/20"
676
+ : "border-ews-gray-300 focus:border-ews-primary focus:ring-ews-primary/20",
677
+ // Hover state
678
+ !disabled && !hasError && "hover:border-ews-gray-400",
679
+ // Text color
680
+ "text-ews-gray-900",
681
+ // Padding for icons
682
+ "pr-10", selectClassName), ...props, children: jsxs("div", { className: "flex justify-between items-center", children: [jsx("div", { className: "flex-1 min-w-0", children: selectedOption ? (renderValue ? (renderValue(selectedOption)) : (jsx("span", { className: "truncate", children: selectedOption.label }))) : (jsx("span", { className: "text-ews-gray-500", children: placeholder })) }), jsxs("div", { className: "flex items-center ml-2 space-x-1", children: [clearable && selectedOption && !disabled && (jsx("button", { type: "button", onClick: handleClear, className: "p-1 rounded hover:bg-ews-gray-100", children: jsx(X, { className: cn(iconSizeClasses[size], "text-ews-gray-400") }) })), jsx(ChevronDown, { className: cn(iconSizeClasses[size], hasError ? "text-ews-error" : "text-ews-gray-400", disabled && "text-ews-gray-300", isOpen && "rotate-180 transition-transform") })] })] }) }), isOpen && (jsxs("div", { ref: dropdownRef, role: "listbox", className: cn("absolute z-50 w-full bg-white rounded-md border shadow-lg border-ews-gray-300", "focus:outline-none", dropdownPosition === "top"
683
+ ? "bottom-full mb-1"
684
+ : "top-full mt-1", dropdownClassName), style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsx("div", { className: "p-2 border-b border-ews-gray-200", children: jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute left-3 top-1/2 w-4 h-4 transform -translate-y-1/2 text-ews-gray-400" }), jsx("input", { ref: inputRef, type: "text", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), placeholder: "Search options...", className: "py-2 pr-3 pl-9 w-full text-sm rounded-md border border-ews-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-ews-primary/20 focus:border-ews-primary" })] }) })), jsx("div", { className: "overflow-auto py-1", style: { maxHeight: `${maxHeight - (searchable ? 60 : 0)}px` }, children: filteredOptions.length === 0 ? (jsx("div", { className: "px-3 py-2 text-sm text-ews-gray-500", children: searchTerm ? "No options found" : "No options available" })) : (filteredOptions.map((option, index) => {
685
+ const isSelected = option.value === value;
686
+ const isFocused = index === focusedIndex;
687
+ return (jsx("div", { ref: (el) => (optionRefs.current[index] = el), role: "option", "aria-selected": isSelected, onClick: () => handleSelect(option), className: cn("px-3 py-2 text-sm cursor-pointer transition-colors", isSelected && "bg-ews-primary text-white", !isSelected && isFocused && "bg-ews-gray-100", !isSelected && !isFocused && "hover:bg-ews-gray-50", option.disabled && "opacity-50 cursor-not-allowed"), children: renderOption ? (renderOption(option, isSelected)) : (jsx("span", { className: "truncate", children: option.label })) }, `${String(option.value)}-${index}`));
688
+ })) })] }))] }), (helperText || error) && (jsx("div", { className: "mt-1", children: error ? (jsx("p", { className: "text-sm text-ews-error", children: error })) : (jsx("p", { className: "text-sm text-ews-gray-500", children: helperText })) }))] }));
689
+ });
690
+ Select.displayName = "Select";
691
+
454
692
  const DEFAULT_DELAY = 500;
455
693
  /**
456
694
  * A custom hook that debounces a value
@@ -499,6 +737,506 @@ function useDebouncedCallback(callback, delay) {
499
737
  return debouncedCallback;
500
738
  }
501
739
 
740
+ var isCheckBoxInput = (element) => element.type === 'checkbox';
741
+
742
+ var isDateObject = (value) => value instanceof Date;
743
+
744
+ var isNullOrUndefined = (value) => value == null;
745
+
746
+ const isObjectType = (value) => typeof value === 'object';
747
+ var isObject = (value) => !isNullOrUndefined(value) &&
748
+ !Array.isArray(value) &&
749
+ isObjectType(value) &&
750
+ !isDateObject(value);
751
+
752
+ var getEventValue = (event) => isObject(event) && event.target
753
+ ? isCheckBoxInput(event.target)
754
+ ? event.target.checked
755
+ : event.target.value
756
+ : event;
757
+
758
+ var getNodeParentName = (name) => name.substring(0, name.search(/\.\d+(\.|$)/)) || name;
759
+
760
+ var isNameInFieldArray = (names, name) => names.has(getNodeParentName(name));
761
+
762
+ var isPlainObject = (tempObject) => {
763
+ const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
764
+ return (isObject(prototypeCopy) && prototypeCopy.hasOwnProperty('isPrototypeOf'));
765
+ };
766
+
767
+ var isWeb = typeof window !== 'undefined' &&
768
+ typeof window.HTMLElement !== 'undefined' &&
769
+ typeof document !== 'undefined';
770
+
771
+ function cloneObject(data) {
772
+ let copy;
773
+ const isArray = Array.isArray(data);
774
+ const isFileListInstance = typeof FileList !== 'undefined' ? data instanceof FileList : false;
775
+ if (data instanceof Date) {
776
+ copy = new Date(data);
777
+ }
778
+ else if (!(isWeb && (data instanceof Blob || isFileListInstance)) &&
779
+ (isArray || isObject(data))) {
780
+ copy = isArray ? [] : Object.create(Object.getPrototypeOf(data));
781
+ if (!isArray && !isPlainObject(data)) {
782
+ copy = data;
783
+ }
784
+ else {
785
+ for (const key in data) {
786
+ if (data.hasOwnProperty(key)) {
787
+ copy[key] = cloneObject(data[key]);
788
+ }
789
+ }
790
+ }
791
+ }
792
+ else {
793
+ return data;
794
+ }
795
+ return copy;
796
+ }
797
+
798
+ var isKey = (value) => /^\w*$/.test(value);
799
+
800
+ var isUndefined = (val) => val === undefined;
801
+
802
+ var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
803
+
804
+ var stringToPath = (input) => compact(input.replace(/["|']|\]/g, '').split(/\.|\[/));
805
+
806
+ var get = (object, path, defaultValue) => {
807
+ if (!path || !isObject(object)) {
808
+ return defaultValue;
809
+ }
810
+ const result = (isKey(path) ? [path] : stringToPath(path)).reduce((result, key) => isNullOrUndefined(result) ? result : result[key], object);
811
+ return isUndefined(result) || result === object
812
+ ? isUndefined(object[path])
813
+ ? defaultValue
814
+ : object[path]
815
+ : result;
816
+ };
817
+
818
+ var isBoolean = (value) => typeof value === 'boolean';
819
+
820
+ var set = (object, path, value) => {
821
+ let index = -1;
822
+ const tempPath = isKey(path) ? [path] : stringToPath(path);
823
+ const length = tempPath.length;
824
+ const lastIndex = length - 1;
825
+ while (++index < length) {
826
+ const key = tempPath[index];
827
+ let newValue = value;
828
+ if (index !== lastIndex) {
829
+ const objValue = object[key];
830
+ newValue =
831
+ isObject(objValue) || Array.isArray(objValue)
832
+ ? objValue
833
+ : !isNaN(+tempPath[index + 1])
834
+ ? []
835
+ : {};
836
+ }
837
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
838
+ return;
839
+ }
840
+ object[key] = newValue;
841
+ object = object[key];
842
+ }
843
+ };
844
+
845
+ const EVENTS = {
846
+ BLUR: 'blur',
847
+ CHANGE: 'change',
848
+ };
849
+ const VALIDATION_MODE = {
850
+ all: 'all',
851
+ };
852
+
853
+ const HookFormContext = React.createContext(null);
854
+ HookFormContext.displayName = 'HookFormContext';
855
+ /**
856
+ * This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would become inconvenient to pass the context as a prop. To be used with {@link FormProvider}.
857
+ *
858
+ * @remarks
859
+ * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
860
+ *
861
+ * @returns return all useForm methods
862
+ *
863
+ * @example
864
+ * ```tsx
865
+ * function App() {
866
+ * const methods = useForm();
867
+ * const onSubmit = data => console.log(data);
868
+ *
869
+ * return (
870
+ * <FormProvider {...methods} >
871
+ * <form onSubmit={methods.handleSubmit(onSubmit)}>
872
+ * <NestedInput />
873
+ * <input type="submit" />
874
+ * </form>
875
+ * </FormProvider>
876
+ * );
877
+ * }
878
+ *
879
+ * function NestedInput() {
880
+ * const { register } = useFormContext(); // retrieve all hook methods
881
+ * return <input {...register("test")} />;
882
+ * }
883
+ * ```
884
+ */
885
+ const useFormContext = () => React.useContext(HookFormContext);
886
+
887
+ var getProxyFormState = (formState, control, localProxyFormState, isRoot = true) => {
888
+ const result = {
889
+ defaultValues: control._defaultValues,
890
+ };
891
+ for (const key in formState) {
892
+ Object.defineProperty(result, key, {
893
+ get: () => {
894
+ const _key = key;
895
+ if (control._proxyFormState[_key] !== VALIDATION_MODE.all) {
896
+ control._proxyFormState[_key] = !isRoot || VALIDATION_MODE.all;
897
+ }
898
+ localProxyFormState && (localProxyFormState[_key] = true);
899
+ return formState[_key];
900
+ },
901
+ });
902
+ }
903
+ return result;
904
+ };
905
+
906
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
907
+
908
+ /**
909
+ * This custom hook allows you to subscribe to each form state, and isolate the re-render at the custom hook level. It has its scope in terms of form state subscription, so it would not affect other useFormState and useForm. Using this hook can reduce the re-render impact on large and complex form application.
910
+ *
911
+ * @remarks
912
+ * [API](https://react-hook-form.com/docs/useformstate) • [Demo](https://codesandbox.io/s/useformstate-75xly)
913
+ *
914
+ * @param props - include options on specify fields to subscribe. {@link UseFormStateReturn}
915
+ *
916
+ * @example
917
+ * ```tsx
918
+ * function App() {
919
+ * const { register, handleSubmit, control } = useForm({
920
+ * defaultValues: {
921
+ * firstName: "firstName"
922
+ * }});
923
+ * const { dirtyFields } = useFormState({
924
+ * control
925
+ * });
926
+ * const onSubmit = (data) => console.log(data);
927
+ *
928
+ * return (
929
+ * <form onSubmit={handleSubmit(onSubmit)}>
930
+ * <input {...register("firstName")} placeholder="First Name" />
931
+ * {dirtyFields.firstName && <p>Field is dirty.</p>}
932
+ * <input type="submit" />
933
+ * </form>
934
+ * );
935
+ * }
936
+ * ```
937
+ */
938
+ function useFormState(props) {
939
+ const methods = useFormContext();
940
+ const { control = methods.control, disabled, name, exact } = props || {};
941
+ const [formState, updateFormState] = React.useState(control._formState);
942
+ const _localProxyFormState = React.useRef({
943
+ isDirty: false,
944
+ isLoading: false,
945
+ dirtyFields: false,
946
+ touchedFields: false,
947
+ validatingFields: false,
948
+ isValidating: false,
949
+ isValid: false,
950
+ errors: false,
951
+ });
952
+ useIsomorphicLayoutEffect(() => control._subscribe({
953
+ name,
954
+ formState: _localProxyFormState.current,
955
+ exact,
956
+ callback: (formState) => {
957
+ !disabled &&
958
+ updateFormState({
959
+ ...control._formState,
960
+ ...formState,
961
+ });
962
+ },
963
+ }), [name, disabled, exact]);
964
+ React.useEffect(() => {
965
+ _localProxyFormState.current.isValid && control._setValid(true);
966
+ }, [control]);
967
+ return React.useMemo(() => getProxyFormState(formState, control, _localProxyFormState.current, false), [formState, control]);
968
+ }
969
+
970
+ var isString = (value) => typeof value === 'string';
971
+
972
+ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) => {
973
+ if (isString(names)) {
974
+ return get(formValues, names, defaultValue);
975
+ }
976
+ if (Array.isArray(names)) {
977
+ return names.map((fieldName) => (get(formValues, fieldName)));
978
+ }
979
+ return formValues;
980
+ };
981
+
982
+ var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
983
+
984
+ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
985
+ if (isPrimitive(object1) || isPrimitive(object2)) {
986
+ return object1 === object2;
987
+ }
988
+ if (isDateObject(object1) && isDateObject(object2)) {
989
+ return object1.getTime() === object2.getTime();
990
+ }
991
+ const keys1 = Object.keys(object1);
992
+ const keys2 = Object.keys(object2);
993
+ if (keys1.length !== keys2.length) {
994
+ return false;
995
+ }
996
+ if (_internal_visited.has(object1) || _internal_visited.has(object2)) {
997
+ return true;
998
+ }
999
+ _internal_visited.add(object1);
1000
+ _internal_visited.add(object2);
1001
+ for (const key of keys1) {
1002
+ const val1 = object1[key];
1003
+ if (!keys2.includes(key)) {
1004
+ return false;
1005
+ }
1006
+ if (key !== 'ref') {
1007
+ const val2 = object2[key];
1008
+ if ((isDateObject(val1) && isDateObject(val2)) ||
1009
+ (isObject(val1) && isObject(val2)) ||
1010
+ (Array.isArray(val1) && Array.isArray(val2))
1011
+ ? !deepEqual(val1, val2, _internal_visited)
1012
+ : val1 !== val2) {
1013
+ return false;
1014
+ }
1015
+ }
1016
+ }
1017
+ return true;
1018
+ }
1019
+
1020
+ /**
1021
+ * Custom hook to subscribe to field change and isolate re-rendering at the component level.
1022
+ *
1023
+ * @remarks
1024
+ *
1025
+ * [API](https://react-hook-form.com/docs/usewatch) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-usewatch-h9i5e)
1026
+ *
1027
+ * @example
1028
+ * ```tsx
1029
+ * const { control } = useForm();
1030
+ * const values = useWatch({
1031
+ * name: "fieldName"
1032
+ * control,
1033
+ * })
1034
+ * ```
1035
+ */
1036
+ function useWatch(props) {
1037
+ const methods = useFormContext();
1038
+ const { control = methods.control, name, defaultValue, disabled, exact, compute, } = props || {};
1039
+ const _defaultValue = React.useRef(defaultValue);
1040
+ const _compute = React.useRef(compute);
1041
+ const _computeFormValues = React.useRef(undefined);
1042
+ _compute.current = compute;
1043
+ const defaultValueMemo = React.useMemo(() => control._getWatch(name, _defaultValue.current), [control, name]);
1044
+ const [value, updateValue] = React.useState(_compute.current ? _compute.current(defaultValueMemo) : defaultValueMemo);
1045
+ useIsomorphicLayoutEffect(() => control._subscribe({
1046
+ name,
1047
+ formState: {
1048
+ values: true,
1049
+ },
1050
+ exact,
1051
+ callback: (formState) => {
1052
+ if (!disabled) {
1053
+ const formValues = generateWatchOutput(name, control._names, formState.values || control._formValues, false, _defaultValue.current);
1054
+ if (_compute.current) {
1055
+ const computedFormValues = _compute.current(formValues);
1056
+ if (!deepEqual(computedFormValues, _computeFormValues.current)) {
1057
+ updateValue(computedFormValues);
1058
+ _computeFormValues.current = computedFormValues;
1059
+ }
1060
+ }
1061
+ else {
1062
+ updateValue(formValues);
1063
+ }
1064
+ }
1065
+ },
1066
+ }), [control, disabled, name, exact]);
1067
+ React.useEffect(() => control._removeUnmounted());
1068
+ return value;
1069
+ }
1070
+
1071
+ /**
1072
+ * Custom hook to work with controlled component, this function provide you with both form and field level state. Re-render is isolated at the hook level.
1073
+ *
1074
+ * @remarks
1075
+ * [API](https://react-hook-form.com/docs/usecontroller) • [Demo](https://codesandbox.io/s/usecontroller-0o8px)
1076
+ *
1077
+ * @param props - the path name to the form field value, and validation rules.
1078
+ *
1079
+ * @returns field properties, field and form state. {@link UseControllerReturn}
1080
+ *
1081
+ * @example
1082
+ * ```tsx
1083
+ * function Input(props) {
1084
+ * const { field, fieldState, formState } = useController(props);
1085
+ * return (
1086
+ * <div>
1087
+ * <input {...field} placeholder={props.name} />
1088
+ * <p>{fieldState.isTouched && "Touched"}</p>
1089
+ * <p>{formState.isSubmitted ? "submitted" : ""}</p>
1090
+ * </div>
1091
+ * );
1092
+ * }
1093
+ * ```
1094
+ */
1095
+ function useController(props) {
1096
+ const methods = useFormContext();
1097
+ const { name, disabled, control = methods.control, shouldUnregister, defaultValue, } = props;
1098
+ const isArrayField = isNameInFieldArray(control._names.array, name);
1099
+ const defaultValueMemo = React.useMemo(() => get(control._formValues, name, get(control._defaultValues, name, defaultValue)), [control, name, defaultValue]);
1100
+ const value = useWatch({
1101
+ control,
1102
+ name,
1103
+ defaultValue: defaultValueMemo,
1104
+ exact: true,
1105
+ });
1106
+ const formState = useFormState({
1107
+ control,
1108
+ name,
1109
+ exact: true,
1110
+ });
1111
+ const _props = React.useRef(props);
1112
+ const _registerProps = React.useRef(control.register(name, {
1113
+ ...props.rules,
1114
+ value,
1115
+ ...(isBoolean(props.disabled) ? { disabled: props.disabled } : {}),
1116
+ }));
1117
+ _props.current = props;
1118
+ const fieldState = React.useMemo(() => Object.defineProperties({}, {
1119
+ invalid: {
1120
+ enumerable: true,
1121
+ get: () => !!get(formState.errors, name),
1122
+ },
1123
+ isDirty: {
1124
+ enumerable: true,
1125
+ get: () => !!get(formState.dirtyFields, name),
1126
+ },
1127
+ isTouched: {
1128
+ enumerable: true,
1129
+ get: () => !!get(formState.touchedFields, name),
1130
+ },
1131
+ isValidating: {
1132
+ enumerable: true,
1133
+ get: () => !!get(formState.validatingFields, name),
1134
+ },
1135
+ error: {
1136
+ enumerable: true,
1137
+ get: () => get(formState.errors, name),
1138
+ },
1139
+ }), [formState, name]);
1140
+ const onChange = React.useCallback((event) => _registerProps.current.onChange({
1141
+ target: {
1142
+ value: getEventValue(event),
1143
+ name: name,
1144
+ },
1145
+ type: EVENTS.CHANGE,
1146
+ }), [name]);
1147
+ const onBlur = React.useCallback(() => _registerProps.current.onBlur({
1148
+ target: {
1149
+ value: get(control._formValues, name),
1150
+ name: name,
1151
+ },
1152
+ type: EVENTS.BLUR,
1153
+ }), [name, control._formValues]);
1154
+ const ref = React.useCallback((elm) => {
1155
+ const field = get(control._fields, name);
1156
+ if (field && elm) {
1157
+ field._f.ref = {
1158
+ focus: () => elm.focus && elm.focus(),
1159
+ select: () => elm.select && elm.select(),
1160
+ setCustomValidity: (message) => elm.setCustomValidity(message),
1161
+ reportValidity: () => elm.reportValidity(),
1162
+ };
1163
+ }
1164
+ }, [control._fields, name]);
1165
+ const field = React.useMemo(() => ({
1166
+ name,
1167
+ value,
1168
+ ...(isBoolean(disabled) || formState.disabled
1169
+ ? { disabled: formState.disabled || disabled }
1170
+ : {}),
1171
+ onChange,
1172
+ onBlur,
1173
+ ref,
1174
+ }), [name, disabled, formState.disabled, onChange, onBlur, ref, value]);
1175
+ React.useEffect(() => {
1176
+ const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
1177
+ control.register(name, {
1178
+ ..._props.current.rules,
1179
+ ...(isBoolean(_props.current.disabled)
1180
+ ? { disabled: _props.current.disabled }
1181
+ : {}),
1182
+ });
1183
+ const updateMounted = (name, value) => {
1184
+ const field = get(control._fields, name);
1185
+ if (field && field._f) {
1186
+ field._f.mount = value;
1187
+ }
1188
+ };
1189
+ updateMounted(name, true);
1190
+ if (_shouldUnregisterField) {
1191
+ const value = cloneObject(get(control._options.defaultValues, name));
1192
+ set(control._defaultValues, name, value);
1193
+ if (isUndefined(get(control._formValues, name))) {
1194
+ set(control._formValues, name, value);
1195
+ }
1196
+ }
1197
+ !isArrayField && control.register(name);
1198
+ return () => {
1199
+ (isArrayField
1200
+ ? _shouldUnregisterField && !control._state.action
1201
+ : _shouldUnregisterField)
1202
+ ? control.unregister(name)
1203
+ : updateMounted(name, false);
1204
+ };
1205
+ }, [name, control, isArrayField, shouldUnregister]);
1206
+ React.useEffect(() => {
1207
+ control._setDisabledField({
1208
+ disabled,
1209
+ name,
1210
+ });
1211
+ }, [disabled, name, control]);
1212
+ return React.useMemo(() => ({
1213
+ field,
1214
+ formState,
1215
+ fieldState,
1216
+ }), [field, formState, fieldState]);
1217
+ }
1218
+
1219
+ function useSelectField({ name, control, options: _options, rules, defaultValue, }) {
1220
+ const { field, fieldState: { error, invalid }, } = useController({
1221
+ name,
1222
+ control,
1223
+ rules,
1224
+ defaultValue,
1225
+ });
1226
+ const selectProps = {
1227
+ value: field.value,
1228
+ onChange: (value) => field.onChange(value),
1229
+ isError: invalid,
1230
+ error: error?.message,
1231
+ };
1232
+ return {
1233
+ selectProps,
1234
+ field,
1235
+ error,
1236
+ invalid,
1237
+ };
1238
+ }
1239
+
502
1240
  function SearchAutocomplete({ onSelect, selectedId, searchFunction, getEntityById, getDisplayValue, getSecondaryText, placeholder, icon = Search, disabled = false, minSearchLength = 2, debounceTime = 300, error, }) {
503
1241
  const [searchTerm, setSearchTerm] = useState("");
504
1242
  const [entities, setEntities] = useState([]);
@@ -628,7 +1366,7 @@ function SearchAutocomplete({ onSelect, selectedId, searchFunction, getEntityByI
628
1366
  : "No results found. Try a different search term." })), isLoading && showDropdown && (jsx("div", { className: "absolute z-10 p-4 mt-1 w-full text-center text-gray-500 bg-white rounded-md shadow-lg", children: jsxs("div", { className: "flex justify-center items-center", children: [jsx("div", { className: "mr-2 w-4 h-4 rounded-full border-b-2 animate-spin border-ews-primary" }), "Loading..."] }) }))] }));
629
1367
  }
630
1368
 
631
- function MultiSearchAutocomplete({ items, selectedItems, onSelectionChange, onSearch, getEntityById, getPrimaryText, getSecondaryText, placeholder, disabled = false, loading = false, multiple = true, className, renderSelectedItem, renderListItem, keepOpenOnSelect = true, error, minSearchLength = 2, debounceTime = 300, }) {
1369
+ function MultiSearchAutocomplete({ items, selectedItems, onSelectionChange, onSearch, getEntityById: _getEntityById, getPrimaryText, getSecondaryText, placeholder, disabled = false, loading = false, multiple = true, className, renderSelectedItem, renderListItem, keepOpenOnSelect = true, error, minSearchLength = 2, debounceTime = 300, }) {
632
1370
  const [searchTerm, setSearchTerm] = useState("");
633
1371
  const [isOpen, setIsOpen] = useState(false);
634
1372
  const [filteredItems, setFilteredItems] = useState(items);
@@ -812,7 +1550,7 @@ const Modal = ({ isOpen, onClose, title, children, variant = "info", primaryActi
812
1550
  return (jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [jsx("div", { className: "absolute inset-0 bg-black/50 backdrop-blur-sm", onClick: handleOverlayClick }), jsxs("div", { className: cn("relative w-full max-w-md mx-4 bg-white rounded-lg shadow-xl transform transition-all", "animate-in fade-in-0 zoom-in-95 duration-200", className), role: "dialog", "aria-modal": "true", "aria-labelledby": "modal-title", children: [jsxs("div", { className: cn("flex items-center justify-between p-6 border-b", variantStyles.borderColor), children: [jsxs("div", { className: "flex items-center space-x-3", children: [jsx("div", { className: cn("p-2 rounded-full", variantStyles.iconBg), children: variantStyles.icon }), jsx("h2", { id: "modal-title", className: cn("text-lg font-semibold", variantStyles.titleColor), children: title })] }), jsx("button", { onClick: onClose, className: "p-1 text-gray-400 hover:text-gray-600 transition-colors", "aria-label": "Close modal", children: jsx(X, { className: "w-5 h-5" }) })] }), jsx("div", { className: cn("p-6", contentClassName), children: jsx("div", { className: "text-gray-700 leading-relaxed", children: error && variant === "error" ? (jsxs("div", { className: "space-y-3", children: [jsx("p", { children: error.message }), error.fields && error.fields.length > 0 && (jsxs("div", { children: [jsx("p", { className: "font-semibold text-gray-900", children: "Erreurs de champ:" }), jsx("ul", { className: "mt-2 space-y-1", children: error.fields.map((field, index) => (jsxs("li", { className: "text-ews-error", children: ["\u2022 ", field.path, ": ", field.message] }, index))) })] }))] })) : (children) }) }), (primaryAction || secondaryAction) && (jsxs("div", { className: "flex items-center justify-end space-x-3 p-6 pt-0", children: [secondaryAction && (jsx(Button, { variant: "ghost", onClick: onSecondaryAction || onClose, disabled: isLoading, children: secondaryAction })), primaryAction && (jsx(Button, { variant: variant === "error" ? "error" : "primary", onClick: onPrimaryAction, loading: isLoading, children: primaryAction }))] }))] })] }));
813
1551
  };
814
1552
 
815
- const Logo = ({ size = "md", showTagline = true, iconOnly = false, variant = "normal", className, onClick, }) => {
1553
+ const Logo = ({ size = "md", showTagline: _showTagline = true, iconOnly = false, variant = "normal", className, onClick, }) => {
816
1554
  const sizes = {
817
1555
  sm: "h-8",
818
1556
  md: "h-12",
@@ -931,6 +1669,21 @@ const ThemeToggle = ({ className }) => {
931
1669
  : "text-gray-600 hover:text-gray-900"}`, children: "MED" })] })] }));
932
1670
  };
933
1671
 
1672
+ const ThemeDebugger = ({ className = "", }) => {
1673
+ const { theme, themeConfig, setTheme } = useTheme();
1674
+ const getComputedStyleValue = (property) => {
1675
+ if (typeof window !== "undefined") {
1676
+ return getComputedStyle(document.documentElement).getPropertyValue(property);
1677
+ }
1678
+ return "N/A";
1679
+ };
1680
+ return (jsxs("div", { className: `p-4 border rounded-lg bg-gray-50 ${className}`, children: [jsx("h3", { className: "text-lg font-semibold mb-4", children: "Theme Debugger" }), jsxs("div", { className: "space-y-3", children: [jsxs("div", { children: [jsx("strong", { children: "Current Theme:" }), " ", theme] }), jsxs("div", { children: [jsx("strong", { children: "Theme Config:" }), jsx("pre", { className: "text-xs bg-gray-100 p-2 rounded mt-1", children: JSON.stringify(themeConfig, null, 2) })] }), jsxs("div", { children: [jsx("strong", { children: "CSS Variables:" }), jsxs("div", { className: "text-xs space-y-1 mt-1", children: [jsxs("div", { children: ["--ews-primary: ", getComputedStyleValue("--ews-primary")] }), jsxs("div", { children: ["--ews-secondary: ", getComputedStyleValue("--ews-secondary")] }), jsxs("div", { children: ["--ews-primary-hover:", " ", getComputedStyleValue("--ews-primary-hover")] }), jsxs("div", { children: ["--ews-secondary-hover:", " ", getComputedStyleValue("--ews-secondary-hover")] })] })] }), jsxs("div", { children: [jsx("strong", { children: "Data Theme Attribute:" }), " ", document.documentElement.getAttribute("data-theme")] }), jsxs("div", { className: "flex space-x-2", children: [jsx("button", { onClick: () => setTheme("PROMED"), className: `px-3 py-1 text-xs rounded ${theme === "PROMED"
1681
+ ? "bg-ews-primary text-white"
1682
+ : "bg-gray-200 text-gray-700"}`, children: "PROMED" }), jsx("button", { onClick: () => setTheme("MED"), className: `px-3 py-1 text-xs rounded ${theme === "MED"
1683
+ ? "bg-ews-primary text-white"
1684
+ : "bg-gray-200 text-gray-700"}`, children: "MED" })] }), jsxs("div", { className: "grid grid-cols-2 gap-2 mt-4", children: [jsx("div", { className: "bg-ews-primary text-white p-2 rounded text-center", children: "Primary" }), jsx("div", { className: "bg-ews-secondary text-white p-2 rounded text-center", children: "Secondary" }), jsx("div", { className: "bg-ews-success text-white p-2 rounded text-center", children: "Success" }), jsx("div", { className: "bg-ews-warning text-white p-2 rounded text-center", children: "Warning" })] })] })] }));
1685
+ };
1686
+
934
1687
  const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesChange, placeholder = "Search and select medical specialties...", className = "", disabled = false, maxSelections, showSelectedCount = true, }) => {
935
1688
  const [specialties, setSpecialties] = useState([]);
936
1689
  const [isLoading, setIsLoading] = useState(false);
@@ -990,5 +1743,5 @@ const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesCh
990
1743
  : "border-gray-300"), children: isSelected && (jsx("svg", { className: "w-3 h-3 text-white", fill: "currentColor", viewBox: "0 0 20 20", children: jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) })) }), jsxs("div", { className: "flex flex-col", children: [jsx("span", { className: cn("font-medium", isSelected ? "text-ews-primary" : "text-gray-900"), children: specialty.label }), jsx("span", { className: cn("text-sm", isSelected ? "text-ews-primary/70" : "text-gray-500"), children: specialty.code })] })] })) }), showSelectedCount && selectedSpecialties.length > 0 && (jsxs("div", { className: "flex items-center justify-between text-sm text-gray-600", children: [jsxs("span", { children: [selectedSpecialties.length, " specialty", selectedSpecialties.length !== 1 ? "ies" : "", " selected"] }), maxSelections && (jsxs("span", { className: "text-gray-400", children: [selectedSpecialties.length, "/", maxSelections] }))] }))] }));
991
1744
  };
992
1745
 
993
- export { ArrowRight, Button, Check, DoctorIcon, Icon, Input, Logo, Modal, MultiSearchAutocomplete, PatientIcon, Search, SearchAutocomplete, SpecialtySearchAutocomplete, ThemeProvider, ThemeToggle, UserIcon, cn, debounce, formatCurrency, formatDate, generateId, useDebounce, useDebouncedCallback, useTheme };
1746
+ export { ArrowRight, Button, Check, DoctorIcon, Icon, Input, Logo, Modal, MultiSearchAutocomplete, PatientIcon, Search, SearchAutocomplete, Select, SpecialtySearchAutocomplete, ThemeDebugger, ThemeProvider, ThemeToggle, UserIcon, cn, debounce, formatCurrency, formatDate, generateId, useDebounce, useDebouncedCallback, useSelectField, useTheme };
994
1747
  //# sourceMappingURL=index.esm.js.map