@rovula/ui 0.0.77 → 0.0.79

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 (57) hide show
  1. package/dist/cjs/bundle.css +43 -3
  2. package/dist/cjs/bundle.js +3 -3
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/Dropdown/Dropdown.d.ts +3 -0
  5. package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +5 -1
  6. package/dist/cjs/types/components/MaskedTextInput/MaskedTextInput.d.ts +75 -0
  7. package/dist/cjs/types/components/MaskedTextInput/MaskedTextInput.stories.d.ts +491 -0
  8. package/dist/cjs/types/components/MaskedTextInput/index.d.ts +3 -0
  9. package/dist/cjs/types/components/Menu/Menu.d.ts +65 -0
  10. package/dist/cjs/types/components/Menu/Menu.stories.d.ts +31 -0
  11. package/dist/cjs/types/components/Menu/helpers.d.ts +19 -0
  12. package/dist/cjs/types/components/Menu/index.d.ts +4 -0
  13. package/dist/cjs/types/components/Search/Search.d.ts +46 -3
  14. package/dist/cjs/types/components/Search/Search.stories.d.ts +46 -27
  15. package/dist/cjs/types/index.d.ts +3 -0
  16. package/dist/components/Dropdown/Dropdown.js +41 -19
  17. package/dist/components/Dropdown/Dropdown.stories.js +13 -0
  18. package/dist/components/MaskedTextInput/MaskedTextInput.js +267 -0
  19. package/dist/components/MaskedTextInput/MaskedTextInput.stories.js +167 -0
  20. package/dist/components/MaskedTextInput/index.js +2 -0
  21. package/dist/components/Menu/Menu.js +64 -0
  22. package/dist/components/Menu/Menu.stories.js +406 -0
  23. package/dist/components/Menu/helpers.js +28 -0
  24. package/dist/components/Menu/index.js +3 -0
  25. package/dist/components/Toast/Toast.styles.js +1 -1
  26. package/dist/esm/bundle.css +43 -3
  27. package/dist/esm/bundle.js +3 -3
  28. package/dist/esm/bundle.js.map +1 -1
  29. package/dist/esm/types/components/Dropdown/Dropdown.d.ts +3 -0
  30. package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +5 -1
  31. package/dist/esm/types/components/MaskedTextInput/MaskedTextInput.d.ts +75 -0
  32. package/dist/esm/types/components/MaskedTextInput/MaskedTextInput.stories.d.ts +491 -0
  33. package/dist/esm/types/components/MaskedTextInput/index.d.ts +3 -0
  34. package/dist/esm/types/components/Menu/Menu.d.ts +65 -0
  35. package/dist/esm/types/components/Menu/Menu.stories.d.ts +31 -0
  36. package/dist/esm/types/components/Menu/helpers.d.ts +19 -0
  37. package/dist/esm/types/components/Menu/index.d.ts +4 -0
  38. package/dist/esm/types/components/Search/Search.d.ts +46 -3
  39. package/dist/esm/types/components/Search/Search.stories.d.ts +46 -27
  40. package/dist/esm/types/index.d.ts +3 -0
  41. package/dist/index.d.ts +169 -3
  42. package/dist/index.js +2 -0
  43. package/dist/src/theme/global.css +55 -4
  44. package/package.json +1 -1
  45. package/src/components/Dropdown/Dropdown.stories.tsx +31 -0
  46. package/src/components/Dropdown/Dropdown.tsx +73 -54
  47. package/src/components/MaskedTextInput/MaskedTextInput.stories.tsx +414 -0
  48. package/src/components/MaskedTextInput/MaskedTextInput.tsx +391 -0
  49. package/src/components/MaskedTextInput/README.md +202 -0
  50. package/src/components/MaskedTextInput/index.ts +3 -0
  51. package/src/components/Menu/Menu.stories.tsx +586 -0
  52. package/src/components/Menu/Menu.tsx +235 -0
  53. package/src/components/Menu/helpers.ts +45 -0
  54. package/src/components/Menu/index.ts +7 -0
  55. package/src/components/Search/Search.tsx +24 -11
  56. package/src/components/Toast/Toast.styles.tsx +1 -1
  57. package/src/index.ts +6 -0
@@ -2344,16 +2344,20 @@ input[type=number] {
2344
2344
  z-index: 10;
2345
2345
  }
2346
2346
 
2347
+ .z-40 {
2348
+ z-index: 40;
2349
+ }
2350
+
2347
2351
  .z-50 {
2348
2352
  z-index: 50;
2349
2353
  }
2350
2354
 
2351
- .z-\[100\] {
2352
- z-index: 100;
2355
+ .z-\[1000\] {
2356
+ z-index: 1000;
2353
2357
  }
2354
2358
 
2355
- .z-\[9999\] {
2356
- z-index: 9999;
2359
+ .z-\[100\] {
2360
+ z-index: 100;
2357
2361
  }
2358
2362
 
2359
2363
  .col-span-3 {
@@ -2708,6 +2712,10 @@ input[type=number] {
2708
2712
  width: 2rem;
2709
2713
  }
2710
2714
 
2715
+ .w-80 {
2716
+ width: 20rem;
2717
+ }
2718
+
2711
2719
  .w-\[100px\] {
2712
2720
  width: 100px;
2713
2721
  }
@@ -2778,6 +2786,10 @@ input[type=number] {
2778
2786
  min-width: fit-content;
2779
2787
  }
2780
2788
 
2789
+ .max-w-2xl {
2790
+ max-width: 42rem;
2791
+ }
2792
+
2781
2793
  .max-w-\[300px\] {
2782
2794
  max-width: 300px;
2783
2795
  }
@@ -2790,6 +2802,10 @@ input[type=number] {
2790
2802
  max-width: 32rem;
2791
2803
  }
2792
2804
 
2805
+ .max-w-md {
2806
+ max-width: 28rem;
2807
+ }
2808
+
2793
2809
  .flex-1 {
2794
2810
  flex: 1 1 0%;
2795
2811
  }
@@ -3891,6 +3907,11 @@ input[type=number] {
3891
3907
  background-color: color-mix(in srgb, var(--function-default-stroke) calc(100% * var(--tw-bg-opacity, 1)), transparent);
3892
3908
  }
3893
3909
 
3910
+ .bg-gray-100 {
3911
+ --tw-bg-opacity: 1;
3912
+ background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
3913
+ }
3914
+
3894
3915
  .bg-gray-200 {
3895
3916
  --tw-bg-opacity: 1;
3896
3917
  background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1));
@@ -5527,6 +5548,11 @@ input[type=number] {
5527
5548
  font-weight: var(--label-label2-weight, 400);
5528
5549
  }
5529
5550
 
5551
+ .text-lg {
5552
+ font-size: 1.125rem;
5553
+ line-height: 1.75rem;
5554
+ }
5555
+
5530
5556
  .text-sm {
5531
5557
  font-size: 0.875rem;
5532
5558
  line-height: 1.25rem;
@@ -5640,6 +5666,10 @@ input[type=number] {
5640
5666
  font-weight: 500;
5641
5667
  }
5642
5668
 
5669
+ .font-semibold {
5670
+ font-weight: 600;
5671
+ }
5672
+
5643
5673
  .uppercase {
5644
5674
  text-transform: uppercase;
5645
5675
  }
@@ -5893,6 +5923,11 @@ input[type=number] {
5893
5923
  color: rgb(107 114 128 / var(--tw-text-opacity, 1));
5894
5924
  }
5895
5925
 
5926
+ .text-gray-700 {
5927
+ --tw-text-opacity: 1;
5928
+ color: rgb(55 65 81 / var(--tw-text-opacity, 1));
5929
+ }
5930
+
5896
5931
  .text-green-500 {
5897
5932
  --tw-text-opacity: 1;
5898
5933
  color: rgb(34 197 94 / var(--tw-text-opacity, 1));
@@ -6029,6 +6064,10 @@ input[type=number] {
6029
6064
  caret-color: color-mix(in srgb, var(--state-color-primary-default) calc(100% * 1), transparent);
6030
6065
  }
6031
6066
 
6067
+ .opacity-50 {
6068
+ opacity: 0.5;
6069
+ }
6070
+
6032
6071
  .opacity-60 {
6033
6072
  opacity: 0.6;
6034
6073
  }
@@ -6539,6 +6578,10 @@ input[type=number] {
6539
6578
  border-color: color-mix(in srgb, var(--input-color-active-stroke) calc(100% * var(--tw-border-opacity, 1)), transparent);
6540
6579
  }
6541
6580
 
6581
+ .hover\:bg-\[var\(--dropdown-menu-hover-bg\)\]:hover {
6582
+ background-color: var(--dropdown-menu-hover-bg);
6583
+ }
6584
+
6542
6585
  .hover\:bg-action-button-icon-active-hover:hover {
6543
6586
  --tw-bg-opacity: 1;
6544
6587
  background-color: color-mix(in srgb, var(--action-button-icon-active-hover-bg) calc(100% * var(--tw-bg-opacity, 1)), transparent);
@@ -6810,6 +6853,10 @@ input[type=number] {
6810
6853
  fill: color-mix(in srgb, var(--input-color-default-text) calc(100% * 1), transparent);
6811
6854
  }
6812
6855
 
6856
+ .hover\:text-\[var\(--dropdown-menu-hover-text\)\]:hover {
6857
+ color: var(--dropdown-menu-hover-text);
6858
+ }
6859
+
6813
6860
  .hover\:text-action-button-icon-active-hover:hover {
6814
6861
  --tw-text-opacity: 1;
6815
6862
  color: color-mix(in srgb, var(--action-button-icon-active-hover-text) calc(100% * var(--tw-text-opacity, 1)), transparent);
@@ -8870,6 +8917,10 @@ input[type=number] {
8870
8917
  .md\:right-\[40px\] {
8871
8918
  right: 40px;
8872
8919
  }
8920
+
8921
+ .md\:grid-cols-2 {
8922
+ grid-template-columns: repeat(2, minmax(0, 1fr));
8923
+ }
8873
8924
  }
8874
8925
 
8875
8926
  .\[\&\:has\(\[role\=checkbox\]\)\]\:w-4:has([role=checkbox]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rovula/ui",
3
- "version": "0.0.77",
3
+ "version": "0.0.79",
4
4
  "main": "dist/cjs/bundle.js",
5
5
  "module": "dist/esm/bundle.js",
6
6
  "types": "dist/index.d.ts",
@@ -3,6 +3,8 @@ import type { Meta, StoryObj } from "@storybook/react";
3
3
  import Dropdown, { Options } from "./Dropdown";
4
4
  import Button from "../Button/Button";
5
5
  import { cn } from "@/utils/cn";
6
+ import { MenuItemType } from "../Menu/Menu";
7
+ import Icon from "../Icon/Icon";
6
8
 
7
9
  // More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
8
10
  const meta = {
@@ -167,3 +169,32 @@ export const CustomOption = {
167
169
  );
168
170
  },
169
171
  } satisfies StoryObj;
172
+
173
+ // ==================== Advanced Menu Features ====================
174
+
175
+ export const WithIcons: StoryObj<typeof Dropdown> = {
176
+ render: () => {
177
+ const [selectedValue, setSelectedValue] = useState<Options | undefined>();
178
+
179
+ const optionsWithIcons: Options[] = [
180
+ { value: "apple", label: "🍎 Apple" },
181
+ { value: "banana", label: "🍌 Banana" },
182
+ { value: "carrot", label: "🥕 Carrot" },
183
+ { value: "broccoli", label: "🥦 Broccoli" },
184
+ ];
185
+
186
+ return (
187
+ <div className="flex flex-row gap-4 w-full">
188
+ <Dropdown
189
+ id="with-icons"
190
+ size="lg"
191
+ label="Select Food"
192
+ fullwidth
193
+ options={optionsWithIcons}
194
+ value={selectedValue}
195
+ onSelect={(option) => setSelectedValue(option)}
196
+ />
197
+ </div>
198
+ );
199
+ },
200
+ };
@@ -1,6 +1,5 @@
1
1
  import React, {
2
2
  CSSProperties,
3
- Fragment,
4
3
  ReactNode,
5
4
  forwardRef,
6
5
  useCallback,
@@ -9,10 +8,12 @@ import React, {
9
8
  useMemo,
10
9
  useRef,
11
10
  useState,
11
+ Fragment,
12
12
  } from "react";
13
13
  import * as Portal from "@radix-ui/react-portal";
14
14
  import TextInput, { InputProps } from "../TextInput/TextInput";
15
15
  import { customInputVariant, dropdownIconVariant } from "./Dropdown.styles";
16
+ import { Menu, MenuItemType, MenuOption } from "../Menu/Menu";
16
17
 
17
18
  import { ChevronDownIcon } from "@heroicons/react/16/solid";
18
19
  import { cn } from "@/utils/cn";
@@ -36,6 +37,7 @@ export type DropdownProps = {
36
37
  size?: "sm" | "md" | "lg";
37
38
  rounded?: "none" | "normal" | "full";
38
39
  variant?: "flat" | "outline" | "underline";
40
+ defaultMenuItemType?: MenuOption["type"];
39
41
  helperText?: string;
40
42
  errorMessage?: string;
41
43
  filterMode?: boolean;
@@ -71,6 +73,7 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
71
73
  size = "md",
72
74
  rounded = "normal",
73
75
  variant = "outline",
76
+ defaultMenuItemType = "checkbox",
74
77
  helperText,
75
78
  errorMessage,
76
79
  fullwidth = true,
@@ -211,66 +214,82 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
211
214
  });
212
215
  }
213
216
 
214
- return (
215
- <ul
216
- className={cn(
217
- "absolute mt-1 w-full bg-base-popup border border-base-popup text-base-popup-foreground rounded-md shadow-md z-[9999] max-h-60 overflow-y-auto",
218
- !usePortal && (isAbove ? "bottom-full mb-1" : "top-full mt-1"),
219
- optionContainerClassName
220
- )}
221
- style={dropdownStyles}
222
- ref={dropdownRef}
223
- >
224
- {optionsFiltered.map((option) => {
225
- if (option.renderLabel) {
226
- return (
227
- <Fragment key={option.value}>
228
- {option.renderLabel({
229
- value: option.value,
230
- label: option.label,
231
- handleOnClick: () => handleOptionClick(option),
232
- className: cn(
233
- `px-4 py-2 hover:bg-primary-hover-bg cursor-pointer`,
234
- optionItemClassName,
235
- {
236
- "bg-base-popup-highligh":
237
- selectedOption?.value === option.value,
238
- }
239
- ),
240
- })}
241
- </Fragment>
242
- );
243
- }
244
- return (
245
- <li
246
- key={option.value}
247
- onMouseDown={() => {
248
- handleOptionClick(option);
249
- }}
250
- className={cn(
251
- `px-4 py-2 hover:bg-primary-hover-bg cursor-pointer`,
252
- optionItemClassName,
253
- {
254
- "bg-base-popup-highligh":
255
- selectedOption?.value === option.value,
256
- }
257
- )}
258
- >
259
- {option.label}
260
- </li>
261
- );
262
- })}
263
- {optionsFiltered.length === 0 && (
264
- <li
217
+ // Convert options to MenuItemType
218
+ let finalMenuItems: MenuItemType[];
219
+
220
+ finalMenuItems = optionsFiltered.map((option) => {
221
+ if (option.renderLabel) {
222
+ return {
223
+ type: "custom",
224
+ render: () => (
225
+ <Fragment key={option.value}>
226
+ {option.renderLabel!({
227
+ value: option.value,
228
+ label: option.label,
229
+ handleOnClick: () => handleOptionClick(option),
230
+ className: cn(
231
+ "relative flex gap-3 cursor-pointer select-none box-border items-center py-4 pl-9 pr-4 typography-subtitile4 outline-none transition-colors",
232
+ "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]",
233
+ "active:opacity-75",
234
+ "hover:bg-[var(--dropdown-menu-hover-bg)] hover:text-[var(--dropdown-menu-hover-text)]",
235
+ {
236
+ "bg-[var(--dropdown-menu-selected-bg)] text-[var(--dropdown-menu-selected-text)] typography-subtitile5":
237
+ selectedOption?.value === option.value,
238
+ },
239
+ optionItemClassName
240
+ ),
241
+ })}
242
+ </Fragment>
243
+ ),
244
+ };
245
+ }
246
+
247
+ return {
248
+ type: "item",
249
+ item: {
250
+ type: defaultMenuItemType,
251
+ value: option.value,
252
+ label: option.label,
253
+ },
254
+ };
255
+ });
256
+
257
+ // Add "not found" message if no results
258
+ if (finalMenuItems.length === 0) {
259
+ finalMenuItems.push({
260
+ type: "custom",
261
+ render: () => (
262
+ <div
263
+ key="not-found"
265
264
  className={cn(
266
265
  "px-4 py-14 text-center text-input-text",
267
266
  optionNotFoundItemClassName
268
267
  )}
269
268
  >
270
269
  Not found
271
- </li>
270
+ </div>
271
+ ),
272
+ });
273
+ }
274
+
275
+ return (
276
+ <Menu
277
+ ref={dropdownRef as any}
278
+ items={finalMenuItems}
279
+ selectedValues={selectedOption?.value ? [selectedOption.value] : []}
280
+ onSelect={(value) => {
281
+ const option = optionsFiltered.find((opt) => opt.value === value);
282
+ if (option) {
283
+ handleOptionClick(option);
284
+ }
285
+ }}
286
+ className={cn(
287
+ "absolute mt-1 w-full max-h-60 overflow-y-auto",
288
+ !usePortal && (isAbove ? "bottom-full mb-1" : "top-full mt-1"),
289
+ optionContainerClassName
272
290
  )}
273
- </ul>
291
+ style={dropdownStyles}
292
+ />
274
293
  );
275
294
  };
276
295