@genspectrum/dashboard-components 0.4.0 → 0.4.1

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.
@@ -767,20 +767,20 @@ declare global {
767
767
 
768
768
  declare global {
769
769
  interface HTMLElementTagNameMap {
770
- 'gs-location-filter': LocationFilterComponent;
770
+ 'gs-text-input': TextInputComponent;
771
771
  }
772
772
  interface HTMLElementEventMap {
773
- 'gs-location-changed': CustomEvent<Record<string, string>>;
773
+ 'gs-text-input-changed': CustomEvent<Record<string, string>>;
774
774
  }
775
775
  }
776
776
 
777
777
 
778
778
  declare global {
779
779
  interface HTMLElementTagNameMap {
780
- 'gs-text-input': TextInputComponent;
780
+ 'gs-location-filter': LocationFilterComponent;
781
781
  }
782
782
  interface HTMLElementEventMap {
783
- 'gs-text-input-changed': CustomEvent<Record<string, string>>;
783
+ 'gs-location-changed': CustomEvent<Record<string, string>>;
784
784
  }
785
785
  }
786
786
 
package/dist/style.css CHANGED
@@ -1016,15 +1016,6 @@ html {
1016
1016
  color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
1017
1017
  }
1018
1018
 
1019
- .menu li > *:not(ul, .menu-title, details, .btn):active,
1020
- .menu li > *:not(ul, .menu-title, details, .btn).active,
1021
- .menu li > details > summary:active {
1022
- --tw-bg-opacity: 1;
1023
- background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));
1024
- --tw-text-opacity: 1;
1025
- color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)));
1026
- }
1027
-
1028
1019
  .tab:hover {
1029
1020
  --tw-text-opacity: 1;
1030
1021
  }
@@ -1143,39 +1134,6 @@ html {
1143
1134
  transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
1144
1135
  transition-duration: 200ms;
1145
1136
  }
1146
- .dropdown-end .dropdown-content {
1147
- inset-inline-end: 0px;
1148
- }
1149
- .dropdown-left .dropdown-content {
1150
- bottom: auto;
1151
- inset-inline-end: 100%;
1152
- top: 0px;
1153
- transform-origin: right;
1154
- }
1155
- .dropdown-right .dropdown-content {
1156
- bottom: auto;
1157
- inset-inline-start: 100%;
1158
- top: 0px;
1159
- transform-origin: left;
1160
- }
1161
- .dropdown-bottom .dropdown-content {
1162
- bottom: auto;
1163
- top: 100%;
1164
- transform-origin: top;
1165
- }
1166
- .dropdown-top .dropdown-content {
1167
- bottom: 100%;
1168
- top: auto;
1169
- transform-origin: bottom;
1170
- }
1171
- .dropdown-end.dropdown-right .dropdown-content {
1172
- bottom: 0px;
1173
- top: auto;
1174
- }
1175
- .dropdown-end.dropdown-left .dropdown-content {
1176
- bottom: 0px;
1177
- top: auto;
1178
- }
1179
1137
  .dropdown.dropdown-open .dropdown-content,
1180
1138
  .dropdown:not(.dropdown-hover):focus .dropdown-content,
1181
1139
  .dropdown:focus-within .dropdown-content {
@@ -1270,19 +1228,6 @@ html {
1270
1228
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1271
1229
  }
1272
1230
 
1273
- :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):not(.active, .btn):hover, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):not(.active, .btn):hover {
1274
- cursor: pointer;
1275
- outline: 2px solid transparent;
1276
- outline-offset: 2px;
1277
- }
1278
-
1279
- @supports (color: oklch(0% 0 0)) {
1280
-
1281
- :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):not(.active, .btn):hover, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):not(.active, .btn):hover {
1282
- background-color: var(--fallback-bc,oklch(var(--bc)/0.1));
1283
- }
1284
- }
1285
-
1286
1231
  .tab[disabled],
1287
1232
  .tab[disabled]:hover {
1288
1233
  cursor: not-allowed;
@@ -1409,31 +1354,6 @@ html {
1409
1354
  border-radius: inherit;
1410
1355
  }
1411
1356
  }
1412
- .menu {
1413
- display: flex;
1414
- flex-direction: column;
1415
- flex-wrap: wrap;
1416
- font-size: 0.875rem;
1417
- line-height: 1.25rem;
1418
- padding: 0.5rem;
1419
- }
1420
- .menu :where(li ul) {
1421
- position: relative;
1422
- white-space: nowrap;
1423
- margin-inline-start: 1rem;
1424
- padding-inline-start: 0.5rem;
1425
- }
1426
- .menu :where(li:not(.menu-title) > *:not(ul, details, .menu-title, .btn)), .menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
1427
- display: grid;
1428
- grid-auto-flow: column;
1429
- align-content: flex-start;
1430
- align-items: center;
1431
- gap: 0.5rem;
1432
- grid-auto-columns: minmax(auto, max-content) auto max-content;
1433
- -webkit-user-select: none;
1434
- -moz-user-select: none;
1435
- user-select: none;
1436
- }
1437
1357
  .menu li.disabled {
1438
1358
  cursor: not-allowed;
1439
1359
  -webkit-user-select: none;
@@ -1441,20 +1361,6 @@ html {
1441
1361
  user-select: none;
1442
1362
  color: var(--fallback-bc,oklch(var(--bc)/0.3));
1443
1363
  }
1444
- .menu :where(li > .menu-dropdown:not(.menu-dropdown-show)) {
1445
- display: none;
1446
- }
1447
- :where(.menu li) {
1448
- position: relative;
1449
- display: flex;
1450
- flex-shrink: 0;
1451
- flex-direction: column;
1452
- flex-wrap: wrap;
1453
- align-items: stretch;
1454
- }
1455
- :where(.menu li) .badge {
1456
- justify-self: end;
1457
- }
1458
1364
  .modal {
1459
1365
  pointer-events: none;
1460
1366
  position: fixed;
@@ -1678,6 +1584,29 @@ input.tab:checked + .tab-content,
1678
1584
  --tw-bg-opacity: 1;
1679
1585
  background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));
1680
1586
  }
1587
+ .toggle {
1588
+ flex-shrink: 0;
1589
+ --tglbg: var(--fallback-b1,oklch(var(--b1)/1));
1590
+ --handleoffset: 1.5rem;
1591
+ --handleoffsetcalculator: calc(var(--handleoffset) * -1);
1592
+ --togglehandleborder: 0 0;
1593
+ height: 1.5rem;
1594
+ width: 3rem;
1595
+ cursor: pointer;
1596
+ -webkit-appearance: none;
1597
+ -moz-appearance: none;
1598
+ appearance: none;
1599
+ border-radius: var(--rounded-badge, 1.9rem);
1600
+ border-width: 1px;
1601
+ border-color: currentColor;
1602
+ background-color: currentColor;
1603
+ color: var(--fallback-bc,oklch(var(--bc)/0.5));
1604
+ transition: background,
1605
+ box-shadow var(--animation-input, 0.2s) ease-out;
1606
+ box-shadow: var(--handleoffsetcalculator) 0 0 2px var(--tglbg) inset,
1607
+ 0 0 0 2px var(--tglbg) inset,
1608
+ var(--togglehandleborder);
1609
+ }
1681
1610
  .alert-error {
1682
1611
  border-color: var(--fallback-er,oklch(var(--er)/0.2));
1683
1612
  --tw-text-opacity: 1;
@@ -1911,9 +1840,6 @@ input.tab:checked + .tab-content,
1911
1840
  margin-bottom: 0px;
1912
1841
  margin-inline-start: -1px;
1913
1842
  }
1914
- .join-item:focus {
1915
- isolation: isolate;
1916
- }
1917
1843
  .loading {
1918
1844
  pointer-events: none;
1919
1845
  display: inline-block;
@@ -1936,40 +1862,6 @@ input.tab:checked + .tab-content,
1936
1862
  .loading-md {
1937
1863
  width: 1.5rem;
1938
1864
  }
1939
- :where(.menu li:empty) {
1940
- --tw-bg-opacity: 1;
1941
- background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));
1942
- opacity: 0.1;
1943
- margin: 0.5rem 1rem;
1944
- height: 1px;
1945
- }
1946
- .menu :where(li ul):before {
1947
- position: absolute;
1948
- bottom: 0.75rem;
1949
- inset-inline-start: 0px;
1950
- top: 0.75rem;
1951
- width: 1px;
1952
- --tw-bg-opacity: 1;
1953
- background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));
1954
- opacity: 0.1;
1955
- content: "";
1956
- }
1957
- .menu :where(li:not(.menu-title) > *:not(ul, details, .menu-title, .btn)),
1958
- .menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
1959
- border-radius: var(--rounded-btn, 0.5rem);
1960
- padding-left: 1rem;
1961
- padding-right: 1rem;
1962
- padding-top: 0.5rem;
1963
- padding-bottom: 0.5rem;
1964
- text-align: start;
1965
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
1966
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
1967
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
1968
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1969
- transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
1970
- transition-duration: 200ms;
1971
- text-wrap: balance;
1972
- }
1973
1865
  :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):not(summary, .active, .btn).focus, :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):not(summary, .active, .btn):focus, :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):is(summary):not(.active, .btn):focus-visible, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):not(summary, .active, .btn).focus, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):not(summary, .active, .btn):focus, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):is(summary):not(.active, .btn):focus-visible {
1974
1866
  cursor: pointer;
1975
1867
  background-color: var(--fallback-bc,oklch(var(--bc)/0.1));
@@ -1978,38 +1870,6 @@ input.tab:checked + .tab-content,
1978
1870
  outline: 2px solid transparent;
1979
1871
  outline-offset: 2px;
1980
1872
  }
1981
- .menu li > *:not(ul, .menu-title, details, .btn):active,
1982
- .menu li > *:not(ul, .menu-title, details, .btn).active,
1983
- .menu li > details > summary:active {
1984
- --tw-bg-opacity: 1;
1985
- background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));
1986
- --tw-text-opacity: 1;
1987
- color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)));
1988
- }
1989
- .menu :where(li > details > summary)::-webkit-details-marker {
1990
- display: none;
1991
- }
1992
- .menu :where(li > details > summary):after,
1993
- .menu :where(li > .menu-dropdown-toggle):after {
1994
- justify-self: end;
1995
- display: block;
1996
- margin-top: -0.5rem;
1997
- height: 0.5rem;
1998
- width: 0.5rem;
1999
- transform: rotate(45deg);
2000
- transition-property: transform, margin-top;
2001
- transition-duration: 0.3s;
2002
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2003
- content: "";
2004
- transform-origin: 75% 75%;
2005
- box-shadow: 2px 2px;
2006
- pointer-events: none;
2007
- }
2008
- .menu :where(li > details[open] > summary):after,
2009
- .menu :where(li > .menu-dropdown-toggle.menu-dropdown-show):after {
2010
- transform: rotate(225deg);
2011
- margin-top: 0;
2012
- }
2013
1873
  .mockup-phone .display {
2014
1874
  overflow: hidden;
2015
1875
  border-radius: 40px;
@@ -2530,6 +2390,49 @@ input.tab:checked + .tab-content,
2530
2390
  opacity: 1;
2531
2391
  }
2532
2392
  }
2393
+ [dir="rtl"] .toggle {
2394
+ --handleoffsetcalculator: calc(var(--handleoffset) * 1);
2395
+ }
2396
+ .toggle:focus-visible {
2397
+ outline-style: solid;
2398
+ outline-width: 2px;
2399
+ outline-offset: 2px;
2400
+ outline-color: var(--fallback-bc,oklch(var(--bc)/0.2));
2401
+ }
2402
+ .toggle:hover {
2403
+ background-color: currentColor;
2404
+ }
2405
+ .toggle:checked,
2406
+ .toggle[aria-checked="true"] {
2407
+ background-image: none;
2408
+ --handleoffsetcalculator: var(--handleoffset);
2409
+ --tw-text-opacity: 1;
2410
+ color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
2411
+ }
2412
+ [dir="rtl"] .toggle:checked, [dir="rtl"] .toggle[aria-checked="true"] {
2413
+ --handleoffsetcalculator: calc(var(--handleoffset) * -1);
2414
+ }
2415
+ .toggle:indeterminate {
2416
+ --tw-text-opacity: 1;
2417
+ color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
2418
+ box-shadow: calc(var(--handleoffset) / 2) 0 0 2px var(--tglbg) inset,
2419
+ calc(var(--handleoffset) / -2) 0 0 2px var(--tglbg) inset,
2420
+ 0 0 0 2px var(--tglbg) inset;
2421
+ }
2422
+ [dir="rtl"] .toggle:indeterminate {
2423
+ box-shadow: calc(var(--handleoffset) / 2) 0 0 2px var(--tglbg) inset,
2424
+ calc(var(--handleoffset) / -2) 0 0 2px var(--tglbg) inset,
2425
+ 0 0 0 2px var(--tglbg) inset;
2426
+ }
2427
+ .toggle:disabled {
2428
+ cursor: not-allowed;
2429
+ --tw-border-opacity: 1;
2430
+ border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
2431
+ background-color: transparent;
2432
+ opacity: 0.3;
2433
+ --togglehandleborder: 0 0 0 3px var(--fallback-bc,oklch(var(--bc)/1)) inset,
2434
+ var(--handleoffsetcalculator) 0 0 3px var(--fallback-bc,oklch(var(--bc)/1)) inset;
2435
+ }
2533
2436
  .btn-xs {
2534
2437
  height: 1.5rem;
2535
2438
  min-height: 1.5rem;
@@ -2859,18 +2762,21 @@ input.tab:checked + .tab-content,
2859
2762
  .-top-3 {
2860
2763
  top: -0.75rem;
2861
2764
  }
2765
+ .left-0 {
2766
+ left: 0px;
2767
+ }
2862
2768
  .right-2 {
2863
2769
  right: 0.5rem;
2864
2770
  }
2771
+ .top-0 {
2772
+ top: 0px;
2773
+ }
2865
2774
  .top-2 {
2866
2775
  top: 0.5rem;
2867
2776
  }
2868
2777
  .z-10 {
2869
2778
  z-index: 10;
2870
2779
  }
2871
- .z-\[1\] {
2872
- z-index: 1;
2873
- }
2874
2780
  .float-right {
2875
2781
  float: right;
2876
2782
  }
@@ -2895,9 +2801,6 @@ input.tab:checked + .tab-content,
2895
2801
  .mb-2 {
2896
2802
  margin-bottom: 0.5rem;
2897
2803
  }
2898
- .ml-2 {
2899
- margin-left: 0.5rem;
2900
- }
2901
2804
  .mr-2 {
2902
2805
  margin-right: 0.5rem;
2903
2806
  }
@@ -2931,24 +2834,37 @@ input.tab:checked + .tab-content,
2931
2834
  .w-32 {
2932
2835
  width: 8rem;
2933
2836
  }
2837
+ .w-40 {
2838
+ width: 10rem;
2839
+ }
2934
2840
  .w-64 {
2935
2841
  width: 16rem;
2936
2842
  }
2937
- .w-72 {
2938
- width: 18rem;
2939
- }
2940
2843
  .w-full {
2941
2844
  width: 100%;
2942
2845
  }
2846
+ .w-max {
2847
+ width: -moz-max-content;
2848
+ width: max-content;
2849
+ }
2850
+ .min-w-40 {
2851
+ min-width: 10rem;
2852
+ }
2943
2853
  .max-w-screen-lg {
2944
2854
  max-width: 1024px;
2945
2855
  }
2946
2856
  .flex-1 {
2947
2857
  flex: 1 1 0%;
2948
2858
  }
2859
+ .flex-grow {
2860
+ flex-grow: 1;
2861
+ }
2949
2862
  .grow {
2950
2863
  flex-grow: 1;
2951
2864
  }
2865
+ .resize {
2866
+ resize: both;
2867
+ }
2952
2868
  .flex-row {
2953
2869
  flex-direction: row;
2954
2870
  }
@@ -2970,6 +2886,9 @@ input.tab:checked + .tab-content,
2970
2886
  .gap-2 {
2971
2887
  gap: 0.5rem;
2972
2888
  }
2889
+ .gap-y-1 {
2890
+ row-gap: 0.25rem;
2891
+ }
2973
2892
  .overflow-auto {
2974
2893
  overflow: auto;
2975
2894
  }
@@ -2979,18 +2898,9 @@ input.tab:checked + .tab-content,
2979
2898
  .whitespace-nowrap {
2980
2899
  white-space: nowrap;
2981
2900
  }
2982
- .text-nowrap {
2983
- text-wrap: nowrap;
2984
- }
2985
2901
  .break-words {
2986
2902
  overflow-wrap: break-word;
2987
2903
  }
2988
- .rounded {
2989
- border-radius: 0.25rem;
2990
- }
2991
- .rounded-box {
2992
- border-radius: var(--rounded-box, 1rem);
2993
- }
2994
2904
  .rounded-full {
2995
2905
  border-radius: 9999px;
2996
2906
  }
@@ -3033,6 +2943,10 @@ input.tab:checked + .tab-content,
3033
2943
  --tw-border-opacity: 1;
3034
2944
  border-color: rgb(243 244 246 / var(--tw-border-opacity));
3035
2945
  }
2946
+ .border-gray-200 {
2947
+ --tw-border-opacity: 1;
2948
+ border-color: rgb(229 231 235 / var(--tw-border-opacity));
2949
+ }
3036
2950
  .border-gray-300 {
3037
2951
  --tw-border-opacity: 1;
3038
2952
  border-color: rgb(209 213 219 / var(--tw-border-opacity));
@@ -3045,10 +2959,6 @@ input.tab:checked + .tab-content,
3045
2959
  --tw-border-opacity: 1;
3046
2960
  border-color: rgb(239 68 68 / var(--tw-border-opacity));
3047
2961
  }
3048
- .bg-base-100 {
3049
- --tw-bg-opacity: 1;
3050
- background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));
3051
- }
3052
2962
  .bg-base-200 {
3053
2963
  --tw-bg-opacity: 1;
3054
2964
  background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));
@@ -3063,6 +2973,9 @@ input.tab:checked + .tab-content,
3063
2973
  .p-2 {
3064
2974
  padding: 0.5rem;
3065
2975
  }
2976
+ .p-4 {
2977
+ padding: 1rem;
2978
+ }
3066
2979
  .px-2 {
3067
2980
  padding-left: 0.5rem;
3068
2981
  padding-right: 0.5rem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -57,6 +57,7 @@
57
57
  ],
58
58
  "dependencies": {
59
59
  "@floating-ui/dom": "^1.6.5",
60
+ "@floating-ui/utils": "^0.2.2",
60
61
  "@lit/context": "^1.1.1",
61
62
  "@lit/reactive-element": "^2.0.4",
62
63
  "@lit/task": "^1.0.0",
@@ -41,7 +41,6 @@ export const SegmentSelector: FunctionComponent<SegmentSelectorProps> = ({
41
41
 
42
42
  return (
43
43
  <CheckboxSelector
44
- className='mx-1'
45
44
  items={displayedSegments}
46
45
  label={getSegmentSelectorLabel(displayedSegments, prefix || 'Segments: ')}
47
46
  setItems={(items) => setDisplayedSegments(items)}
@@ -1,31 +1,29 @@
1
+ import { Dropdown } from './dropdown';
2
+
1
3
  export type CheckboxItem = {
2
4
  label: string;
3
5
  checked: boolean;
4
6
  };
5
7
 
6
8
  export interface CheckboxSelectorProps<Item extends CheckboxItem = CheckboxItem> {
7
- className?: string;
8
9
  items: Item[];
9
10
  label: string;
10
11
  setItems: (items: Item[]) => void;
11
12
  }
12
13
 
13
14
  export const CheckboxSelector = <Item extends CheckboxItem>({
14
- className,
15
15
  items,
16
16
  label,
17
17
  setItems,
18
18
  }: CheckboxSelectorProps<Item>) => {
19
19
  return (
20
- <div class={`dropdown ${className}`}>
21
- <div tabIndex={0} role='button' class='btn btn-xs text-nowrap'>
22
- {label}
23
- </div>
24
- <ul tabIndex={0} class='p-2 shadow menu dropdown-content z-[1] bg-base-100 rounded-box'>
20
+ <Dropdown buttonTitle={label} placement={'bottom-start'}>
21
+ <ul>
25
22
  {items.map((item, index) => (
26
- <li class='flex flex-row items-center' key={item.label}>
23
+ <li className='flex flex-row items-center' key={item.label}>
27
24
  <label>
28
25
  <input
26
+ className={'mr-2'}
29
27
  type='checkbox'
30
28
  id={`item-${index}`}
31
29
  checked={item.checked}
@@ -41,6 +39,6 @@ export const CheckboxSelector = <Item extends CheckboxItem>({
41
39
  </li>
42
40
  ))}
43
41
  </ul>
44
- </div>
42
+ </Dropdown>
45
43
  );
46
44
  };
@@ -0,0 +1,40 @@
1
+ import { flip, offset, shift } from '@floating-ui/dom';
2
+ import { type Placement } from '@floating-ui/utils';
3
+ import { type FunctionComponent } from 'preact';
4
+ import { useRef, useState } from 'preact/hooks';
5
+
6
+ import { useCloseOnClickOutside, useCloseOnEsc, useFloatingUi } from '../shared/floating-ui/hooks';
7
+
8
+ interface DropdownProps {
9
+ buttonTitle: string;
10
+ placement?: Placement;
11
+ }
12
+
13
+ export const dropdownClass =
14
+ 'z-10 absolute w-max top-0 left-0 bg-white p-4 border border-gray-200 shadow-lg rounded-md';
15
+
16
+ export const Dropdown: FunctionComponent<DropdownProps> = ({ children, buttonTitle, placement }) => {
17
+ const [showContent, setShowContent] = useState(false);
18
+ const referenceRef = useRef<HTMLButtonElement>(null);
19
+ const floatingRef = useRef<HTMLDivElement>(null);
20
+
21
+ useFloatingUi(referenceRef, floatingRef, [offset(4), shift(), flip()], placement);
22
+
23
+ useCloseOnClickOutside(floatingRef, referenceRef, setShowContent);
24
+ useCloseOnEsc(setShowContent);
25
+
26
+ const toggle = () => {
27
+ setShowContent(!showContent);
28
+ };
29
+
30
+ return (
31
+ <div>
32
+ <button type='button' className='btn btn-xs whitespace-nowrap' onClick={toggle} ref={referenceRef}>
33
+ {buttonTitle}
34
+ </button>
35
+ <div ref={floatingRef} className={`${dropdownClass} ${showContent ? '' : 'hidden'}`}>
36
+ {children}
37
+ </div>
38
+ </div>
39
+ );
40
+ };