@ews-admin/global-design-system 1.27.0 → 1.29.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/components/SearchAutocomplete/SearchAutocomplete.d.ts +8 -1
- package/dist/components/SearchAutocomplete/SearchAutocomplete.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts +15 -0
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.esm.js +48 -7
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +48 -7
- package/dist/index.js.map +1 -1
- package/dist/molecules/SpecialtySearchAutocomplete/SpecialtySearchAutocomplete.d.ts +6 -0
- package/dist/molecules/SpecialtySearchAutocomplete/SpecialtySearchAutocomplete.d.ts.map +1 -1
- package/dist/utils/env-config.d.ts +5 -0
- package/dist/utils/env-config.d.ts.map +1 -1
- package/package.json +3 -1
- package/src/components/SearchAutocomplete/SearchAutocomplete.tsx +14 -1
- package/src/components/Select/Select.tsx +20 -2
- package/src/molecules/SpecialtySearchAutocomplete/SpecialtySearchAutocomplete.tsx +31 -1
- package/src/utils/env-config.ts +34 -1
|
@@ -17,7 +17,14 @@ interface SearchAutocompleteProps<T extends SearchableEntity> {
|
|
|
17
17
|
minSearchLength?: number;
|
|
18
18
|
debounceTime?: number;
|
|
19
19
|
error?: string;
|
|
20
|
+
/**
|
|
21
|
+
* MED-1501: builds the hint appended to the placeholder while the search
|
|
22
|
+
* term is still too short. Return `null` (or an empty string) to suppress
|
|
23
|
+
* the hint entirely. Defaults to the English "(min. N characters)", so
|
|
24
|
+
* callers that do not pass it keep today's placeholder.
|
|
25
|
+
*/
|
|
26
|
+
getMinCharactersHint?: (minSearchLength: number) => string | null;
|
|
20
27
|
}
|
|
21
|
-
export declare function SearchAutocomplete<T extends SearchableEntity>({ onSelect, selectedId, searchFunction, getEntityById, getDisplayValue, getSecondaryText, placeholder, icon, disabled, minSearchLength, debounceTime, error, }: SearchAutocompleteProps<T>): React.JSX.Element;
|
|
28
|
+
export declare function SearchAutocomplete<T extends SearchableEntity>({ onSelect, selectedId, searchFunction, getEntityById, getDisplayValue, getSecondaryText, placeholder, icon, disabled, minSearchLength, debounceTime, error, getMinCharactersHint, }: SearchAutocompleteProps<T>): React.JSX.Element;
|
|
22
29
|
export {};
|
|
23
30
|
//# sourceMappingURL=SearchAutocomplete.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchAutocomplete.d.ts","sourceRoot":"","sources":["../../../src/components/SearchAutocomplete/SearchAutocomplete.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,cAAc,CAAC;AACrD,OAAO,KAAsC,MAAM,OAAO,CAAC;AAK3D,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,uBAAuB,CAAC,CAAC,SAAS,gBAAgB;IAC1D,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAClD,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACvD,eAAe,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;IACvC,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,CAAC;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"SearchAutocomplete.d.ts","sourceRoot":"","sources":["../../../src/components/SearchAutocomplete/SearchAutocomplete.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,cAAc,CAAC;AACrD,OAAO,KAAsC,MAAM,OAAO,CAAC;AAK3D,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,uBAAuB,CAAC,CAAC,SAAS,gBAAgB;IAC1D,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAClD,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACvD,eAAe,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;IACvC,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,CAAC;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACnE;AAED,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,gBAAgB,EAAE,EAC7D,QAAQ,EACR,UAAU,EACV,cAAc,EACd,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,IAAa,EACb,QAAgB,EAChB,eAAmB,EACnB,YAAkB,EAClB,KAAK,EACL,oBAA0D,GAC3D,EAAE,uBAAuB,CAAC,CAAC,CAAC,qBAsR5B"}
|
|
@@ -92,6 +92,21 @@ export interface SelectProps<T = unknown> {
|
|
|
92
92
|
* avatar menu).
|
|
93
93
|
*/
|
|
94
94
|
renderTrigger?: () => React.ReactNode;
|
|
95
|
+
/**
|
|
96
|
+
* MED-1501: placeholder of the in-dropdown search input, so the caller can
|
|
97
|
+
* translate it. Defaults to the English "Search options...".
|
|
98
|
+
*/
|
|
99
|
+
searchPlaceholder?: string;
|
|
100
|
+
/**
|
|
101
|
+
* MED-1501: text shown when a search matches no option, so the caller can
|
|
102
|
+
* translate it. Defaults to the English "No options found".
|
|
103
|
+
*/
|
|
104
|
+
noOptionsFoundText?: string;
|
|
105
|
+
/**
|
|
106
|
+
* MED-1501: text shown when there is no option at all, so the caller can
|
|
107
|
+
* translate it. Defaults to the English "No options available".
|
|
108
|
+
*/
|
|
109
|
+
noOptionsAvailableText?: string;
|
|
95
110
|
}
|
|
96
111
|
declare const Select: React.ForwardRefExoticComponent<SelectProps<unknown> & React.RefAttributes<HTMLDivElement>>;
|
|
97
112
|
export { Select };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/components/Select/Select.tsx"],"names":[],"mappings":"AACA,OAAO,KAON,MAAM,OAAO,CAAC;AAIf,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,CAAC;IACV;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACvD;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,YAAY,CAAC,EAAE,CACb,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EACvB,UAAU,EAAE,OAAO,KAChB,KAAK,CAAC,SAAS,CAAC;IACrB;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC,SAAS,CAAC;IAClE;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/components/Select/Select.tsx"],"names":[],"mappings":"AACA,OAAO,KAON,MAAM,OAAO,CAAC;AAIf,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,CAAC;IACV;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACvD;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,YAAY,CAAC,EAAE,CACb,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EACvB,UAAU,EAAE,OAAO,KAChB,KAAK,CAAC,SAAS,CAAC;IACrB;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC,SAAS,CAAC;IAClE;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACtC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,QAAA,MAAM,MAAM,6FAscX,CAAC;AAIF,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -201,6 +201,21 @@ interface SelectProps<T = unknown> {
|
|
|
201
201
|
* avatar menu).
|
|
202
202
|
*/
|
|
203
203
|
renderTrigger?: () => React__default.ReactNode;
|
|
204
|
+
/**
|
|
205
|
+
* MED-1501: placeholder of the in-dropdown search input, so the caller can
|
|
206
|
+
* translate it. Defaults to the English "Search options...".
|
|
207
|
+
*/
|
|
208
|
+
searchPlaceholder?: string;
|
|
209
|
+
/**
|
|
210
|
+
* MED-1501: text shown when a search matches no option, so the caller can
|
|
211
|
+
* translate it. Defaults to the English "No options found".
|
|
212
|
+
*/
|
|
213
|
+
noOptionsFoundText?: string;
|
|
214
|
+
/**
|
|
215
|
+
* MED-1501: text shown when there is no option at all, so the caller can
|
|
216
|
+
* translate it. Defaults to the English "No options available".
|
|
217
|
+
*/
|
|
218
|
+
noOptionsAvailableText?: string;
|
|
204
219
|
}
|
|
205
220
|
declare const Select: React__default.ForwardRefExoticComponent<SelectProps<unknown> & React__default.RefAttributes<HTMLDivElement>>;
|
|
206
221
|
|
|
@@ -221,8 +236,15 @@ interface SearchAutocompleteProps<T extends SearchableEntity> {
|
|
|
221
236
|
minSearchLength?: number;
|
|
222
237
|
debounceTime?: number;
|
|
223
238
|
error?: string;
|
|
239
|
+
/**
|
|
240
|
+
* MED-1501: builds the hint appended to the placeholder while the search
|
|
241
|
+
* term is still too short. Return `null` (or an empty string) to suppress
|
|
242
|
+
* the hint entirely. Defaults to the English "(min. N characters)", so
|
|
243
|
+
* callers that do not pass it keep today's placeholder.
|
|
244
|
+
*/
|
|
245
|
+
getMinCharactersHint?: (minSearchLength: number) => string | null;
|
|
224
246
|
}
|
|
225
|
-
declare function SearchAutocomplete<T extends SearchableEntity>({ onSelect, selectedId, searchFunction, getEntityById, getDisplayValue, getSecondaryText, placeholder, icon, disabled, minSearchLength, debounceTime, error, }: SearchAutocompleteProps<T>): React__default.JSX.Element;
|
|
247
|
+
declare function SearchAutocomplete<T extends SearchableEntity>({ onSelect, selectedId, searchFunction, getEntityById, getDisplayValue, getSecondaryText, placeholder, icon, disabled, minSearchLength, debounceTime, error, getMinCharactersHint, }: SearchAutocompleteProps<T>): React__default.JSX.Element;
|
|
226
248
|
|
|
227
249
|
interface MultiSearchAutocompleteProps<T extends SearchableEntity> {
|
|
228
250
|
items: T[];
|
|
@@ -585,6 +607,12 @@ interface SpecialtySearchAutocompleteProps {
|
|
|
585
607
|
title?: string;
|
|
586
608
|
label?: string;
|
|
587
609
|
getSelectedCountText?: (count: number) => React__default.ReactNode;
|
|
610
|
+
/**
|
|
611
|
+
* MED-1499: accessible label / tooltip of the button that removes a
|
|
612
|
+
* selected specialty from its chip. Defaults to the English
|
|
613
|
+
* "Remove specialty".
|
|
614
|
+
*/
|
|
615
|
+
removeSpecialtyLabel?: string;
|
|
588
616
|
}
|
|
589
617
|
declare const SpecialtySearchAutocomplete: React__default.FC<SpecialtySearchAutocompleteProps>;
|
|
590
618
|
|
|
@@ -651,6 +679,11 @@ interface EnvConfig {
|
|
|
651
679
|
* For local development, sensible defaults are provided but can be overridden
|
|
652
680
|
* (e.g. to point BFF URL at a mock server).
|
|
653
681
|
*
|
|
682
|
+
* When env is empty (build without VITE_ENV), the environment is derived from
|
|
683
|
+
* the current host instead of always assuming local, so a deployed build never
|
|
684
|
+
* links to http://local.*.medecine360local.com. A console warning names the
|
|
685
|
+
* derived environment so the misconfigured build stays visible.
|
|
686
|
+
*
|
|
654
687
|
* @param env - The environment name (VITE_ENV value)
|
|
655
688
|
* @param overrides - Optional URL overrides (e.g. for local mock servers)
|
|
656
689
|
*/
|
package/dist/index.esm.js
CHANGED
|
@@ -38,6 +38,29 @@ function buildUrls(environment) {
|
|
|
38
38
|
adminUrl: `https://${prefix}admin.${domain}`,
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Derives the environment from the host the app is served from, for builds
|
|
43
|
+
* that did not set VITE_ENV. Hosts actually served (Traefik rules in
|
|
44
|
+
* infrastructure/medecine360-hetzner/deployment/docker-stack.*.yml):
|
|
45
|
+
* - local: localhost, 127.0.0.1, *.medecine360local.com (local.app., api., ...)
|
|
46
|
+
* - dev: dev.{app,login,dashboard,admin,api}.medecine360.com
|
|
47
|
+
* - qa: qa.{app,login,dashboard,admin,api}.medecine360.com
|
|
48
|
+
* - prod: medecine360.com, {login,dashboard,admin,api}.medecine360.com
|
|
49
|
+
* Any other host (or no window, e.g. SSR or tests) falls back to local.
|
|
50
|
+
*/
|
|
51
|
+
function environmentFromHost() {
|
|
52
|
+
const hostname = typeof window !== "undefined" ? window.location?.hostname?.toLowerCase() : undefined;
|
|
53
|
+
if (!hostname)
|
|
54
|
+
return "local";
|
|
55
|
+
if (hostname === "medecine360.com" || hostname.endsWith(".medecine360.com")) {
|
|
56
|
+
if (hostname.startsWith("dev."))
|
|
57
|
+
return "dev";
|
|
58
|
+
if (hostname.startsWith("qa."))
|
|
59
|
+
return "qa";
|
|
60
|
+
return "prod";
|
|
61
|
+
}
|
|
62
|
+
return "local";
|
|
63
|
+
}
|
|
41
64
|
/**
|
|
42
65
|
* Creates an environment configuration with all derived URLs.
|
|
43
66
|
*
|
|
@@ -47,11 +70,20 @@ function buildUrls(environment) {
|
|
|
47
70
|
* For local development, sensible defaults are provided but can be overridden
|
|
48
71
|
* (e.g. to point BFF URL at a mock server).
|
|
49
72
|
*
|
|
73
|
+
* When env is empty (build without VITE_ENV), the environment is derived from
|
|
74
|
+
* the current host instead of always assuming local, so a deployed build never
|
|
75
|
+
* links to http://local.*.medecine360local.com. A console warning names the
|
|
76
|
+
* derived environment so the misconfigured build stays visible.
|
|
77
|
+
*
|
|
50
78
|
* @param env - The environment name (VITE_ENV value)
|
|
51
79
|
* @param overrides - Optional URL overrides (e.g. for local mock servers)
|
|
52
80
|
*/
|
|
53
81
|
function createEnvConfig(env, overrides) {
|
|
54
|
-
|
|
82
|
+
let environment = env;
|
|
83
|
+
if (!environment) {
|
|
84
|
+
environment = environmentFromHost();
|
|
85
|
+
console.warn(`[env-config] VITE_ENV is not set; using "${environment}" derived from the current host.`);
|
|
86
|
+
}
|
|
55
87
|
const derived = buildUrls(environment);
|
|
56
88
|
return {
|
|
57
89
|
env: environment,
|
|
@@ -32766,7 +32798,7 @@ const Input = React__default.forwardRef(({ className, variant = "default", size
|
|
|
32766
32798
|
});
|
|
32767
32799
|
Input.displayName = "Input";
|
|
32768
32800
|
|
|
32769
|
-
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, renderTrigger, ...props }, ref) => {
|
|
32801
|
+
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, renderTrigger, searchPlaceholder = "Search options...", noOptionsFoundText = "No options found", noOptionsAvailableText = "No options available", ...props }, ref) => {
|
|
32770
32802
|
const generatedId = useId();
|
|
32771
32803
|
const selectId = `select-${generatedId}`;
|
|
32772
32804
|
const hasError = isError || !!error;
|
|
@@ -32975,7 +33007,7 @@ const Select = forwardRef(({ options = [], value, onChange, placeholder = "Selec
|
|
|
32975
33007
|
// Padding for icons
|
|
32976
33008
|
"pr-10", selectClassName), ...props, children: jsx("div", { className: "flex justify-between items-center", children: renderTrigger ? (renderTrigger()) : (jsxs(Fragment, { 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"
|
|
32977
33009
|
? "bottom-full mb-1"
|
|
32978
|
-
: "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:
|
|
33010
|
+
: "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: searchPlaceholder, leftIcon: jsx(Search, { className: "w-4 h-4 text-ews-gray-400" }) })] }) })), 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 ? noOptionsFoundText : noOptionsAvailableText })) : (filteredOptions.map((option, index) => {
|
|
32979
33011
|
const isSelected = option.value === value;
|
|
32980
33012
|
const isFocused = index === focusedIndex;
|
|
32981
33013
|
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}`));
|
|
@@ -33052,7 +33084,7 @@ function useSelectField({ name, control, options: _options, rules, defaultValue,
|
|
|
33052
33084
|
};
|
|
33053
33085
|
}
|
|
33054
33086
|
|
|
33055
|
-
function SearchAutocomplete({ onSelect, selectedId, searchFunction, getEntityById, getDisplayValue, getSecondaryText, placeholder, icon = Search, disabled = false, minSearchLength = 2, debounceTime = 300, error, }) {
|
|
33087
|
+
function SearchAutocomplete({ onSelect, selectedId, searchFunction, getEntityById, getDisplayValue, getSecondaryText, placeholder, icon = Search, disabled = false, minSearchLength = 2, debounceTime = 300, error, getMinCharactersHint = (min) => `(min. ${min} characters)`, }) {
|
|
33056
33088
|
const [searchTerm, setSearchTerm] = useState("");
|
|
33057
33089
|
const [entities, setEntities] = useState([]);
|
|
33058
33090
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -33165,7 +33197,11 @@ function SearchAutocomplete({ onSelect, selectedId, searchFunction, getEntityByI
|
|
|
33165
33197
|
setSearchTerm("");
|
|
33166
33198
|
onSelect("");
|
|
33167
33199
|
};
|
|
33168
|
-
|
|
33200
|
+
const minCharactersHint = getMinCharactersHint(minSearchLength);
|
|
33201
|
+
const inputPlaceholder = minCharactersHint
|
|
33202
|
+
? `${placeholder} ${minCharactersHint}`
|
|
33203
|
+
: placeholder;
|
|
33204
|
+
return (jsxs("div", { className: "relative", ref: dropdownRef, children: [jsxs("div", { className: "relative", children: [jsx(Input, { type: "text", placeholder: inputPlaceholder, value: selectedEntity ? "" : searchTerm, onChange: handleSearchChange, onFocus: () => searchTerm.length >= minSearchLength &&
|
|
33169
33205
|
isUserSearch.current &&
|
|
33170
33206
|
setShowDropdown(true), disabled: disabled, autoComplete: "off", name: "search-autocomplete", leftIcon: React__default.createElement(icon, { size: 16 }) }), selectedEntity && (jsx("button", { type: "button", className: "flex absolute inset-y-0 right-0 items-center pr-3", onClick: handleClearSelection, disabled: disabled, children: jsx(X, { className: "w-5 h-5 text-gray-400 hover:text-gray-500" }) }))] }), selectedEntity && (jsx("div", { className: "p-4 mt-3 rounded-lg border bg-neutral-50 border-neutral-200", children: jsxs("div", { className: "flex justify-between items-center", children: [jsxs("div", { className: "flex items-center", children: [selectedEntity.photoUrl ? (jsx("img", { src: selectedEntity.photoUrl, alt: getDisplayValue(selectedEntity), className: "object-cover mr-3 w-10 h-10 rounded-full" })) : (React__default.createElement(icon, {
|
|
33171
33207
|
className: "w-10 h-10 text-neutral-400 mr-3",
|
|
@@ -35236,7 +35272,7 @@ const PaymentDueBanner = ({ title, subtitle, warning, ctaLabel, onCtaClick, onDi
|
|
|
35236
35272
|
*/
|
|
35237
35273
|
const SecureLoader = ({ label, description }) => (jsx("div", { "data-testid": "secure-loader", className: "flex min-h-screen items-center justify-center bg-gray-100", children: jsxs("div", { className: "flex flex-col items-center rounded-lg bg-white p-6 shadow-lg", children: [jsxs("div", { className: "relative", children: [jsx(Lock, { className: "h-16 w-16 text-gray-500" }), jsx("div", { className: "absolute bottom-2 right-1 h-6 w-6 animate-spin rounded-full border-4 border-gray-300 border-t-green-500" })] }), jsx("p", { className: "mt-4 text-lg text-gray-600", children: label }), description && (jsx("p", { className: "mt-2 text-sm text-gray-500", children: description }))] }) }));
|
|
35238
35274
|
|
|
35239
|
-
const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesChange, specialties: availableSpecialties, placeholder = "Search and select medical specialties...", className = "", disabled = false, maxSelections, showSelectedCount = true, title = "Medical Specialties", label = "Select Specialties", getSelectedCountText, }) => {
|
|
35275
|
+
const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesChange, specialties: availableSpecialties, placeholder = "Search and select medical specialties...", className = "", disabled = false, maxSelections, showSelectedCount = true, title = "Medical Specialties", label = "Select Specialties", getSelectedCountText, removeSpecialtyLabel = "Remove specialty", }) => {
|
|
35240
35276
|
const [filteredSpecialties, setFilteredSpecialties] = useState([]);
|
|
35241
35277
|
const [isLoading, setIsLoading] = useState(false);
|
|
35242
35278
|
// Filter specialties based on search term
|
|
@@ -35267,10 +35303,15 @@ const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesCh
|
|
|
35267
35303
|
}
|
|
35268
35304
|
onSpecialtiesChange(items);
|
|
35269
35305
|
}, [onSpecialtiesChange, maxSelections]);
|
|
35306
|
+
// MED-1499: a selected specialty must be removable from its chip, not only
|
|
35307
|
+
// by toggling it off again in the dropdown list.
|
|
35308
|
+
const handleRemoveSpecialty = useCallback((specialtyToRemove) => {
|
|
35309
|
+
onSpecialtiesChange(selectedSpecialties.filter((specialty) => specialty.id !== specialtyToRemove.id));
|
|
35310
|
+
}, [onSpecialtiesChange, selectedSpecialties]);
|
|
35270
35311
|
const getEntityById = useCallback(async (id) => {
|
|
35271
35312
|
return availableSpecialties.find((specialty) => specialty.id === id);
|
|
35272
35313
|
}, [availableSpecialties]);
|
|
35273
|
-
return (jsxs("div", { className: cn("space-y-3", className), children: [jsxs("div", { className: "flex items-center space-x-2", children: [jsx("div", { className: "flex justify-center items-center w-8 h-8 rounded-lg bg-secondary-100", children: jsx(Stethoscope, { className: "w-4 h-4 text-secondary-600" }) }), jsx("h3", { className: "text-lg font-semibold text-gray-900", children: title || "Medical Specialties" })] }), jsx("div", { children: jsx("label", { className: "block mb-2 text-sm font-medium text-gray-700", children: label || "Select Specialties" }) }), jsx(MultiSearchAutocomplete, { items: filteredSpecialties, selectedItems: selectedSpecialties, onSelectionChange: handleSelectionChange, onSearch: fetchSpecialties, getEntityById: getEntityById, getPrimaryText: (specialty) => specialty.label, getSecondaryText: (specialty) => specialty.code, placeholder: placeholder, disabled: disabled, loading: isLoading, multiple: true, keepOpenOnSelect: true, className: "w-full", renderSelectedItem: (specialty) => (
|
|
35314
|
+
return (jsxs("div", { className: cn("space-y-3", className), children: [jsxs("div", { className: "flex items-center space-x-2", children: [jsx("div", { className: "flex justify-center items-center w-8 h-8 rounded-lg bg-secondary-100", children: jsx(Stethoscope, { className: "w-4 h-4 text-secondary-600" }) }), jsx("h3", { className: "text-lg font-semibold text-gray-900", children: title || "Medical Specialties" })] }), jsx("div", { children: jsx("label", { className: "block mb-2 text-sm font-medium text-gray-700", children: label || "Select Specialties" }) }), jsx(MultiSearchAutocomplete, { items: filteredSpecialties, selectedItems: selectedSpecialties, onSelectionChange: handleSelectionChange, onSearch: fetchSpecialties, getEntityById: getEntityById, getPrimaryText: (specialty) => specialty.label, getSecondaryText: (specialty) => specialty.code, placeholder: placeholder, disabled: disabled, loading: isLoading, multiple: true, keepOpenOnSelect: true, className: "w-full", renderSelectedItem: (specialty) => (jsxs("span", { className: "inline-flex items-center px-3 py-1 text-sm font-medium rounded-full border bg-ews-primary/10 text-ews-primary border-ews-primary/20", children: [specialty.label, jsx("button", { type: "button", onClick: () => handleRemoveSpecialty(specialty), className: "ml-2 text-ews-primary/60 hover:text-ews-primary", disabled: disabled, title: removeSpecialtyLabel, "aria-label": removeSpecialtyLabel, children: jsx(X, { className: "w-3 h-3" }) })] })), renderListItem: (specialty, isSelected) => (jsxs("div", { className: "flex items-center space-x-3", children: [jsx("div", { className: cn("flex justify-center items-center w-5 h-5 rounded border-2", isSelected
|
|
35274
35315
|
? "bg-ews-primary border-ews-primary"
|
|
35275
35316
|
: "border-ews-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" }) })) }), jsx("span", { className: cn("font-medium", isSelected ? "text-ews-primary" : "text-gray-900"), children: specialty.label })] })) }), showSelectedCount && selectedSpecialties.length > 0 && (jsxs("div", { className: "flex justify-between items-center text-sm text-gray-600", children: [jsx("span", { children: getSelectedCountText
|
|
35276
35317
|
? getSelectedCountText(selectedSpecialties.length)
|