@ews-admin/global-design-system 1.6.0 → 1.8.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/dist/index.esm.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import React, { forwardRef, createElement, useState, useRef, useEffect, useId, useCallback, createContext, useContext } from 'react';
3
3
 
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}
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))for(t=0;t<e.length;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);else for(t in e)e[t]&&(n&&(n+=" "),n+=t);return n}function clsx(){for(var e,t,f=0,n="";f<arguments.length;)(e=arguments[f++])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
5
5
 
6
6
  const LOCAL_PORTS = {
7
7
  bff: 8082,
8
8
  loginBff: 8080,
9
9
  app: 3000,
10
- login: 3001,
10
+ login: 4001,
11
11
  dashboard: 3002,
12
12
  admin: 3008,
13
13
  };
@@ -62,7 +62,7 @@ function createEnvConfig(env, overrides) {
62
62
  * Available country codes supported by the platform
63
63
  */
64
64
  const COUNTRY_CODES = [
65
- { code: "+221", country: "SN" }, // Senegal
65
+ { code: "+221", country: "SN" },
66
66
  { code: "+235", country: "TD" }, // Chad
67
67
  ];
68
68
  /**
@@ -32606,11 +32606,11 @@ const Input = React.forwardRef(({ className, variant = "default", size = "md", l
32606
32606
  if (label) {
32607
32607
  // Render checkbox with built-in label
32608
32608
  return (jsx("div", { className: cn("space-y-1", fullWidth ? "w-full" : "w-auto"), children: jsxs("div", { className: "flex items-start space-x-3", children: [jsx("input", { id: inputId, type: actualType, className: cn("mt-0.5", // Slight top margin to align with first line of text
32609
- className), ref: ref, ...props }), jsxs("div", { className: "flex-1", children: [jsxs("label", { htmlFor: inputId, className: "block text-sm font-medium cursor-pointer text-ews-gray-700", children: [label, required && jsx("span", { className: "ml-1 text-ews-error", children: "*" })] }), (error || helperText) && (jsx("p", { className: cn("mt-1 text-sm", error ? "text-ews-error" : "text-ews-gray-500"), children: error || helperText }))] })] }) }));
32609
+ className), ref: ref, onChange: onChange, onBlur: onBlur, ...props }), jsxs("div", { className: "flex-1", children: [jsxs("label", { htmlFor: inputId, className: "block text-sm font-medium cursor-pointer text-ews-gray-700", children: [label, required && jsx("span", { className: "ml-1 text-ews-error", children: "*" })] }), (error || helperText) && (jsx("p", { className: cn("mt-1 text-sm", error ? "text-ews-error" : "text-ews-gray-500"), children: error || helperText }))] })] }) }));
32610
32610
  }
32611
32611
  else {
32612
32612
  // Render just the checkbox for external label usage
32613
- return (jsx("input", { id: inputId, type: actualType, className: cn(className), ref: ref, ...props }));
32613
+ return (jsx("input", { id: inputId, type: actualType, className: cn(className), ref: ref, onChange: onChange, onBlur: onBlur, ...props }));
32614
32614
  }
32615
32615
  }
32616
32616
  // Default rendering for non-checkbox inputs
@@ -32937,23 +32937,29 @@ var isWeb = typeof window !== 'undefined' &&
32937
32937
  typeof document !== 'undefined';
32938
32938
 
32939
32939
  function cloneObject(data) {
32940
+ let copy;
32941
+ const isArray = Array.isArray(data);
32942
+ const isFileListInstance = typeof FileList !== 'undefined' ? data instanceof FileList : false;
32940
32943
  if (data instanceof Date) {
32941
- return new Date(data);
32944
+ copy = new Date(data);
32942
32945
  }
32943
- const isFileListInstance = typeof FileList !== 'undefined' && data instanceof FileList;
32944
- if (isWeb && (data instanceof Blob || isFileListInstance)) {
32945
- return data;
32946
+ else if (!(isWeb && (data instanceof Blob || isFileListInstance)) &&
32947
+ (isArray || isObject(data))) {
32948
+ copy = isArray ? [] : Object.create(Object.getPrototypeOf(data));
32949
+ if (!isArray && !isPlainObject(data)) {
32950
+ copy = data;
32951
+ }
32952
+ else {
32953
+ for (const key in data) {
32954
+ if (data.hasOwnProperty(key)) {
32955
+ copy[key] = cloneObject(data[key]);
32956
+ }
32957
+ }
32958
+ }
32946
32959
  }
32947
- const isArray = Array.isArray(data);
32948
- if (!isArray && !(isObject(data) && isPlainObject(data))) {
32960
+ else {
32949
32961
  return data;
32950
32962
  }
32951
- const copy = isArray ? [] : Object.create(Object.getPrototypeOf(data));
32952
- for (const key in data) {
32953
- if (Object.prototype.hasOwnProperty.call(data, key)) {
32954
- copy[key] = cloneObject(data[key]);
32955
- }
32956
- }
32957
32963
  return copy;
32958
32964
  }
32959
32965
 
@@ -32979,8 +32985,6 @@ var get = (object, path, defaultValue) => {
32979
32985
 
32980
32986
  var isBoolean = (value) => typeof value === 'boolean';
32981
32987
 
32982
- var isFunction = (value) => typeof value === 'function';
32983
-
32984
32988
  var set = (object, path, value) => {
32985
32989
  let index = -1;
32986
32990
  const tempPath = isKey(path) ? [path] : stringToPath(path);
@@ -33008,21 +33012,50 @@ var set = (object, path, value) => {
33008
33012
 
33009
33013
  const EVENTS = {
33010
33014
  BLUR: 'blur',
33011
- CHANGE: 'change'};
33015
+ FOCUS_OUT: 'focusout',
33016
+ CHANGE: 'change',
33017
+ };
33012
33018
  const VALIDATION_MODE = {
33019
+ onBlur: 'onBlur',
33020
+ onChange: 'onChange',
33021
+ onSubmit: 'onSubmit',
33022
+ onTouched: 'onTouched',
33013
33023
  all: 'all',
33014
33024
  };
33015
33025
 
33026
+ const HookFormContext = React.createContext(null);
33027
+ HookFormContext.displayName = 'HookFormContext';
33016
33028
  /**
33017
- * Separate context for `control` to prevent unnecessary rerenders.
33018
- * Internal hooks that only need control use this instead of full form context.
33019
- */
33020
- const HookFormControlContext = React.createContext(null);
33021
- HookFormControlContext.displayName = 'HookFormControlContext';
33022
- /**
33023
- * @internal Internal hook to access only control from context.
33029
+ * 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}.
33030
+ *
33031
+ * @remarks
33032
+ * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
33033
+ *
33034
+ * @returns return all useForm methods
33035
+ *
33036
+ * @example
33037
+ * ```tsx
33038
+ * function App() {
33039
+ * const methods = useForm();
33040
+ * const onSubmit = data => console.log(data);
33041
+ *
33042
+ * return (
33043
+ * <FormProvider {...methods} >
33044
+ * <form onSubmit={methods.handleSubmit(onSubmit)}>
33045
+ * <NestedInput />
33046
+ * <input type="submit" />
33047
+ * </form>
33048
+ * </FormProvider>
33049
+ * );
33050
+ * }
33051
+ *
33052
+ * function NestedInput() {
33053
+ * const { register } = useFormContext(); // retrieve all hook methods
33054
+ * return <input {...register("test")} />;
33055
+ * }
33056
+ * ```
33024
33057
  */
33025
- const useFormControlContext = () => React.useContext(HookFormControlContext);
33058
+ const useFormContext = () => React.useContext(HookFormContext);
33026
33059
 
33027
33060
  var getProxyFormState = (formState, control, localProxyFormState, isRoot = true) => {
33028
33061
  const result = {
@@ -33076,8 +33109,8 @@ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayou
33076
33109
  * ```
33077
33110
  */
33078
33111
  function useFormState(props) {
33079
- const formControl = useFormControlContext();
33080
- const { control = formControl, disabled, name, exact } = props || {};
33112
+ const methods = useFormContext();
33113
+ const { control = methods.control, disabled, name, exact } = props || {};
33081
33114
  const [formState, updateFormState] = React.useState(control._formState);
33082
33115
  const _localProxyFormState = React.useRef({
33083
33116
  isDirty: false,
@@ -33111,11 +33144,14 @@ var isString = (value) => typeof value === 'string';
33111
33144
 
33112
33145
  var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) => {
33113
33146
  if (isString(names)) {
33147
+ isGlobal && _names.watch.add(names);
33114
33148
  return get(formValues, names, defaultValue);
33115
33149
  }
33116
33150
  if (Array.isArray(names)) {
33117
- return names.map((fieldName) => (get(formValues, fieldName)));
33151
+ return names.map((fieldName) => (isGlobal && _names.watch.add(fieldName),
33152
+ get(formValues, fieldName)));
33118
33153
  }
33154
+ isGlobal && (_names.watchAll = true);
33119
33155
  return formValues;
33120
33156
  };
33121
33157
 
@@ -33123,10 +33159,10 @@ var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
33123
33159
 
33124
33160
  function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
33125
33161
  if (isPrimitive(object1) || isPrimitive(object2)) {
33126
- return Object.is(object1, object2);
33162
+ return object1 === object2;
33127
33163
  }
33128
33164
  if (isDateObject(object1) && isDateObject(object2)) {
33129
- return Object.is(object1.getTime(), object2.getTime());
33165
+ return object1.getTime() === object2.getTime();
33130
33166
  }
33131
33167
  const keys1 = Object.keys(object1);
33132
33168
  const keys2 = Object.keys(object2);
@@ -33149,7 +33185,7 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
33149
33185
  (isObject(val1) && isObject(val2)) ||
33150
33186
  (Array.isArray(val1) && Array.isArray(val2))
33151
33187
  ? !deepEqual(val1, val2, _internal_visited)
33152
- : !Object.is(val1, val2)) {
33188
+ : val1 !== val2) {
33153
33189
  return false;
33154
33190
  }
33155
33191
  }
@@ -33174,73 +33210,38 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
33174
33210
  * ```
33175
33211
  */
33176
33212
  function useWatch(props) {
33177
- const formControl = useFormControlContext();
33178
- const { control = formControl, name, defaultValue, disabled, exact, compute, } = props || {};
33213
+ const methods = useFormContext();
33214
+ const { control = methods.control, name, defaultValue, disabled, exact, compute, } = props || {};
33179
33215
  const _defaultValue = React.useRef(defaultValue);
33180
33216
  const _compute = React.useRef(compute);
33181
33217
  const _computeFormValues = React.useRef(undefined);
33182
- const _prevControl = React.useRef(control);
33183
- const _prevName = React.useRef(name);
33184
33218
  _compute.current = compute;
33185
- const [value, updateValue] = React.useState(() => {
33186
- const defaultValue = control._getWatch(name, _defaultValue.current);
33187
- return _compute.current ? _compute.current(defaultValue) : defaultValue;
33188
- });
33189
- const getCurrentOutput = React.useCallback((values) => {
33190
- const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current);
33191
- return _compute.current ? _compute.current(formValues) : formValues;
33192
- }, [control._formValues, control._names, name]);
33193
- const refreshValue = React.useCallback((values) => {
33194
- if (!disabled) {
33195
- const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current);
33196
- if (_compute.current) {
33197
- const computedFormValues = _compute.current(formValues);
33198
- if (!deepEqual(computedFormValues, _computeFormValues.current)) {
33199
- updateValue(computedFormValues);
33200
- _computeFormValues.current = computedFormValues;
33219
+ const defaultValueMemo = React.useMemo(() => control._getWatch(name, _defaultValue.current), [control, name]);
33220
+ const [value, updateValue] = React.useState(_compute.current ? _compute.current(defaultValueMemo) : defaultValueMemo);
33221
+ useIsomorphicLayoutEffect(() => control._subscribe({
33222
+ name,
33223
+ formState: {
33224
+ values: true,
33225
+ },
33226
+ exact,
33227
+ callback: (formState) => {
33228
+ if (!disabled) {
33229
+ const formValues = generateWatchOutput(name, control._names, formState.values || control._formValues, false, _defaultValue.current);
33230
+ if (_compute.current) {
33231
+ const computedFormValues = _compute.current(formValues);
33232
+ if (!deepEqual(computedFormValues, _computeFormValues.current)) {
33233
+ updateValue(computedFormValues);
33234
+ _computeFormValues.current = computedFormValues;
33235
+ }
33236
+ }
33237
+ else {
33238
+ updateValue(formValues);
33201
33239
  }
33202
33240
  }
33203
- else {
33204
- updateValue(formValues);
33205
- }
33206
- }
33207
- }, [control._formValues, control._names, disabled, name]);
33208
- useIsomorphicLayoutEffect(() => {
33209
- if (_prevControl.current !== control ||
33210
- !deepEqual(_prevName.current, name)) {
33211
- _prevControl.current = control;
33212
- _prevName.current = name;
33213
- refreshValue();
33214
- }
33215
- return control._subscribe({
33216
- name,
33217
- formState: {
33218
- values: true,
33219
- },
33220
- exact,
33221
- callback: (formState) => {
33222
- refreshValue(formState.values);
33223
- },
33224
- });
33225
- }, [control, exact, name, refreshValue]);
33241
+ },
33242
+ }), [control, disabled, name, exact]);
33226
33243
  React.useEffect(() => control._removeUnmounted());
33227
- // If name or control changed for this render, synchronously reflect the
33228
- // latest value so callers (like useController) see the correct value
33229
- // immediately on the same render.
33230
- // Optimize: Check control reference first before expensive deepEqual
33231
- const controlChanged = _prevControl.current !== control;
33232
- const prevName = _prevName.current;
33233
- // Cache the computed output to avoid duplicate calls within the same render
33234
- // We include shouldReturnImmediate in deps to ensure proper recomputation
33235
- const computedOutput = React.useMemo(() => {
33236
- if (disabled) {
33237
- return null;
33238
- }
33239
- const nameChanged = !controlChanged && !deepEqual(prevName, name);
33240
- const shouldReturnImmediate = controlChanged || nameChanged;
33241
- return shouldReturnImmediate ? getCurrentOutput() : null;
33242
- }, [disabled, controlChanged, name, prevName, getCurrentOutput]);
33243
- return computedOutput !== null ? computedOutput : value;
33244
+ return value;
33244
33245
  }
33245
33246
 
33246
33247
  /**
@@ -33268,20 +33269,20 @@ function useWatch(props) {
33268
33269
  * ```
33269
33270
  */
33270
33271
  function useController(props) {
33271
- const formControl = useFormControlContext();
33272
- const { name, disabled, control = formControl, shouldUnregister, defaultValue, exact = true, } = props;
33272
+ const methods = useFormContext();
33273
+ const { name, disabled, control = methods.control, shouldUnregister, defaultValue, } = props;
33273
33274
  const isArrayField = isNameInFieldArray(control._names.array, name);
33274
33275
  const defaultValueMemo = React.useMemo(() => get(control._formValues, name, get(control._defaultValues, name, defaultValue)), [control, name, defaultValue]);
33275
33276
  const value = useWatch({
33276
33277
  control,
33277
33278
  name,
33278
33279
  defaultValue: defaultValueMemo,
33279
- exact,
33280
+ exact: true,
33280
33281
  });
33281
33282
  const formState = useFormState({
33282
33283
  control,
33283
33284
  name,
33284
- exact,
33285
+ exact: true,
33285
33286
  });
33286
33287
  const _props = React.useRef(props);
33287
33288
  const _previousNameRef = React.useRef(undefined);
@@ -33329,12 +33330,12 @@ function useController(props) {
33329
33330
  }), [name, control._formValues]);
33330
33331
  const ref = React.useCallback((elm) => {
33331
33332
  const field = get(control._fields, name);
33332
- if (field && field._f && elm) {
33333
+ if (field && elm) {
33333
33334
  field._f.ref = {
33334
- focus: () => isFunction(elm.focus) && elm.focus(),
33335
- select: () => isFunction(elm.select) && elm.select(),
33336
- setCustomValidity: (message) => isFunction(elm.setCustomValidity) && elm.setCustomValidity(message),
33337
- reportValidity: () => isFunction(elm.reportValidity) && elm.reportValidity(),
33335
+ focus: () => elm.focus && elm.focus(),
33336
+ select: () => elm.select && elm.select(),
33337
+ setCustomValidity: (message) => elm.setCustomValidity(message),
33338
+ reportValidity: () => elm.reportValidity(),
33338
33339
  };
33339
33340
  }
33340
33341
  }, [control._fields, name]);
@@ -33368,7 +33369,7 @@ function useController(props) {
33368
33369
  };
33369
33370
  updateMounted(name, true);
33370
33371
  if (_shouldUnregisterField) {
33371
- const value = cloneObject(get(control._options.defaultValues, name, _props.current.defaultValue));
33372
+ const value = cloneObject(get(control._options.defaultValues, name));
33372
33373
  set(control._defaultValues, name, value);
33373
33374
  if (isUndefined(get(control._formValues, name))) {
33374
33375
  set(control._formValues, name, value);
@@ -33441,9 +33442,6 @@ function useController(props) {
33441
33442
  */
33442
33443
  const Controller = (props) => props.render(useController(props));
33443
33444
 
33444
- const HookFormContext = React.createContext(null);
33445
- HookFormContext.displayName = 'HookFormContext';
33446
-
33447
33445
  function useSelectField({ name, control, options: _options, rules, defaultValue, }) {
33448
33446
  const { field, fieldState: { error, invalid }, } = useController({
33449
33447
  name,
@@ -33967,7 +33965,14 @@ const PhoneInput = React.forwardRef(({ countryCode, onCountryCodeChange, onChang
33967
33965
  // when the user changes the dropdown without retyping the number.
33968
33966
  const el = nativeRef.current;
33969
33967
  if (el && onChange) {
33970
- const numeric = formatNumeric(el.value);
33968
+ let numeric = formatNumeric(el.value);
33969
+ // Strip new country code digits if already present at the start
33970
+ // (e.g. local part "221778384499" when switching to +221).
33971
+ const newCodeDigits = formatNumeric(newCode);
33972
+ if (newCodeDigits && numeric.startsWith(newCodeDigits)) {
33973
+ numeric = numeric.slice(newCodeDigits.length);
33974
+ el.value = numeric;
33975
+ }
33971
33976
  const fullValue = numeric ? `${newCode}${numeric}` : "";
33972
33977
  // Pass the value string directly — RHF's Controller field.onChange
33973
33978
  // accepts raw values, avoiding unreliable fake-event parsing.
@@ -33985,7 +33990,14 @@ const PhoneInput = React.forwardRef(({ countryCode, onCountryCodeChange, onChang
33985
33990
  }, [value]);
33986
33991
  const handleChange = (e) => {
33987
33992
  // Enforce digits-only in the displayed field.
33988
- const numeric = formatNumeric(e.target.value);
33993
+ let numeric = formatNumeric(e.target.value);
33994
+ // Strip country code digits if user typed or pasted the full number
33995
+ // (e.g. typed "+221778384499" → formatNumeric gives "221778384499"
33996
+ // which would produce "+221221778384499" without this guard).
33997
+ const codeDigits = formatNumeric(activeCode);
33998
+ if (codeDigits && numeric.startsWith(codeDigits)) {
33999
+ numeric = numeric.slice(codeDigits.length);
34000
+ }
33989
34001
  if (e.target.value !== numeric) {
33990
34002
  e.target.value = numeric;
33991
34003
  }
@@ -34093,8 +34105,8 @@ const PROMED_THEME = {
34093
34105
  const MED_THEME = {
34094
34106
  name: "MED",
34095
34107
  colors: {
34096
- primary: "#3BA1A1", // Teal for patients (calming, trustworthy)
34097
- secondary: "#6B73FF", // Soft purple-blue (suggested secondary for MED)
34108
+ primary: "#3BA1A1",
34109
+ secondary: "#6B73FF",
34098
34110
  primaryHover: "#308181",
34099
34111
  secondaryHover: "#5a61e6",
34100
34112
  primaryLight: "#a8d5d5",