pejay-ui 1.4.3 → 1.5.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.
Files changed (148) hide show
  1. package/README.md +26 -0
  2. package/bin/cli.js +45 -15
  3. package/package.json +2 -1
  4. package/registry/buttons.json +3 -2
  5. package/registry/dropdowns.json +3 -1
  6. package/registry/forms.json +51 -23
  7. package/registry/hotkeys.json +12 -0
  8. package/registry/overlays.json +18 -2
  9. package/registry/panels.json +21 -0
  10. package/registry/skeleton.json +20 -0
  11. package/registry/spinner.json +13 -0
  12. package/templates/button/Button.tsx +8 -7
  13. package/templates/button/README.md +81 -0
  14. package/templates/button/index.ts +1 -2
  15. package/templates/form/{checkbox-group.tsx → choices/checkbox-group.tsx} +1 -1
  16. package/templates/form/{checkbox.tsx → choices/checkbox.tsx} +1 -1
  17. package/templates/form/{radio-group.tsx → choices/radio-group.tsx} +1 -1
  18. package/templates/form/{radio.tsx → choices/radio.tsx} +1 -1
  19. package/templates/form/choices/readme.checkbox-group.md +27 -0
  20. package/templates/form/choices/readme.checkbox.md +26 -0
  21. package/templates/form/choices/readme.radio-group.md +26 -0
  22. package/templates/form/choices/readme.radio.md +24 -0
  23. package/templates/form/choices/readme.switch.md +26 -0
  24. package/templates/form/{switch.tsx → choices/switch.tsx} +1 -1
  25. package/templates/form/{file-input.tsx → file/file-input.tsx} +2 -2
  26. package/templates/form/file/readme.file-input.md +26 -0
  27. package/templates/form/index.ts +19 -22
  28. package/templates/form/{amount-input.tsx → numeric/amount-input.tsx} +2 -2
  29. package/templates/form/{number-input.tsx → numeric/number-input.tsx} +2 -2
  30. package/templates/form/{range-slider.tsx → numeric/range-slider.tsx} +1 -1
  31. package/templates/form/numeric/readme.amount-input.md +27 -0
  32. package/templates/form/numeric/readme.number-input.md +26 -0
  33. package/templates/form/numeric/readme.range-slider.md +27 -0
  34. package/templates/form/{date-picker.tsx → pickers/date-picker.tsx} +2 -2
  35. package/templates/form/{date-range-picker.tsx → pickers/date-range-picker.tsx} +2 -2
  36. package/templates/form/pickers/readme.date-picker.md +26 -0
  37. package/templates/form/pickers/readme.date-range-picker.md +25 -0
  38. package/templates/form/pickers/readme.time-picker.md +25 -0
  39. package/templates/form/pickers/readme.time-range-picker.md +25 -0
  40. package/templates/form/{time-picker.tsx → pickers/time-picker.tsx} +1 -1
  41. package/templates/form/{time-range-picker.tsx → pickers/time-range-picker.tsx} +1 -1
  42. package/templates/form/{input.tsx → text-inputs/input.tsx} +1 -1
  43. package/templates/form/{password-input.tsx → text-inputs/password-input.tsx} +1 -1
  44. package/templates/form/text-inputs/readme.email-input.md +24 -0
  45. package/templates/form/text-inputs/readme.input.md +28 -0
  46. package/templates/form/text-inputs/readme.password-input.md +24 -0
  47. package/templates/form/text-inputs/readme.phone-input.md +24 -0
  48. package/templates/form/text-inputs/readme.textarea.md +24 -0
  49. package/templates/form/text-inputs/readme.url-input.md +23 -0
  50. package/templates/form/{textarea.tsx → text-inputs/textarea.tsx} +1 -1
  51. package/templates/hotkeys/README.md +134 -0
  52. package/templates/hotkeys/components/HotkeyProvider.tsx +78 -0
  53. package/templates/hotkeys/components/HotkeysHelpModal.tsx +102 -0
  54. package/templates/hotkeys/core/key-matcher.ts +106 -0
  55. package/templates/hotkeys/core/registry.ts +39 -0
  56. package/templates/hotkeys/core/types.ts +15 -0
  57. package/templates/hotkeys/hooks/useHotkey.ts +43 -0
  58. package/templates/hotkeys/index.ts +6 -0
  59. package/templates/layouts/lv1/app-layout.tsx +1 -1
  60. package/templates/layouts/lv1/sidebar-menu.tsx +1 -1
  61. package/templates/notes/app-provider/app-provider-side-panel-modals-roadmap.md +606 -0
  62. package/templates/notes/app-provider/manual-open-close-side-panel-and-modal.md +913 -0
  63. package/templates/notes/app-provider/side-panel-card-hooks-and-complexity.md +578 -0
  64. package/templates/notes/under-dev/AppProvider.tsx +92 -0
  65. package/templates/notes/under-dev/app-context.ts +14 -0
  66. package/templates/notes/under-dev/card/base-card.tsx +35 -0
  67. package/templates/notes/under-dev/card/index.ts +4 -0
  68. package/templates/notes/under-dev/card/modal-card.tsx +88 -0
  69. package/templates/notes/under-dev/card/side-panel-card.tsx +127 -0
  70. package/templates/notes/under-dev/form-overlay-registry.ts +42 -0
  71. package/templates/notes/under-dev/keyboard-shortcuts-help.tsx +79 -0
  72. package/templates/notes/under-dev/keyboard-utils.ts +22 -0
  73. package/templates/notes/under-dev/overlay/backdrop.tsx +95 -0
  74. package/templates/notes/under-dev/overlay/index.ts +4 -0
  75. package/templates/notes/under-dev/overlay/modal.tsx +43 -0
  76. package/templates/notes/under-dev/overlay/side-panel.tsx +126 -0
  77. package/templates/notes/under-dev/overlay-close.ts +50 -0
  78. package/templates/notes/under-dev/page-shortcut-registry.ts +9 -0
  79. package/templates/notes/under-dev/unsaved-changes-notify.ts +11 -0
  80. package/templates/notes/under-dev/use-keyboard-shortcuts.tsx +110 -0
  81. package/templates/notes/under-dev/useFormDirty.ts +6 -0
  82. package/templates/notes/under-dev/useFormOverlayRegistration.ts +47 -0
  83. package/templates/notes/under-dev/useFormPanel.tsx +18 -0
  84. package/templates/notes/under-dev/useFormTabHandler.ts +22 -0
  85. package/templates/notes/under-dev/useHorizontalWheelScroll.ts +27 -0
  86. package/templates/notes/under-dev/useOverlay.ts +41 -0
  87. package/templates/overlays/index.ts +2 -1
  88. package/templates/overlays/portal/portal.tsx +26 -0
  89. package/templates/overlays/tooltip/readme.tooltip.md +26 -0
  90. package/templates/{button → overlays/tooltip}/tooltip.tsx +1 -1
  91. package/templates/panels/COMPONENTS.md +103 -0
  92. package/templates/panels/README.md +702 -0
  93. package/templates/panels/components/base-card.tsx +33 -0
  94. package/templates/panels/components/index.ts +8 -0
  95. package/templates/panels/components/modal/backdrop.tsx +88 -0
  96. package/templates/panels/components/modal/modal-card.tsx +139 -0
  97. package/templates/panels/components/modal/modal-raw.tsx +36 -0
  98. package/templates/panels/components/modal/modal.tsx +49 -0
  99. package/templates/panels/components/side-panel/side-panel-card.tsx +123 -0
  100. package/templates/panels/components/side-panel/side-panel-raw.tsx +25 -0
  101. package/templates/panels/components/side-panel/side-panel.tsx +135 -0
  102. package/templates/panels/core/PanelProvider.tsx +145 -0
  103. package/templates/panels/core/constants.ts +9 -0
  104. package/templates/panels/core/form-overlay-registry.ts +35 -0
  105. package/templates/panels/core/index.ts +6 -0
  106. package/templates/panels/core/overlay-close.ts +11 -0
  107. package/templates/panels/core/panel-context.ts +41 -0
  108. package/templates/panels/core/types.ts +41 -0
  109. package/templates/panels/hooks/index.ts +7 -0
  110. package/templates/panels/hooks/useFormDirty.ts +6 -0
  111. package/templates/panels/hooks/useFormOverlayRegistration.ts +92 -0
  112. package/templates/panels/hooks/useFormPanel.tsx +18 -0
  113. package/templates/panels/hooks/useFormTabHandler.ts +25 -0
  114. package/templates/panels/hooks/useHorizontalWheelScroll.ts +31 -0
  115. package/templates/panels/hooks/useModalForm.tsx +22 -0
  116. package/templates/panels/hooks/useOverlay.ts +65 -0
  117. package/templates/panels/index.ts +3 -0
  118. package/templates/panels/vendor-example/by-using-modal/VendorModalPage.tsx +47 -0
  119. package/templates/panels/vendor-example/by-using-modal/useVendorModalForm.tsx +19 -0
  120. package/templates/panels/vendor-example/by-using-modal/vendor-modal-form.tsx +112 -0
  121. package/templates/panels/vendor-example/by-using-modal/vendor-types.ts +29 -0
  122. package/templates/panels/vendor-example/by-using-sidepanel/VendorsPage.tsx +47 -0
  123. package/templates/panels/vendor-example/by-using-sidepanel/useVendorFormPanel.tsx +15 -0
  124. package/templates/panels/vendor-example/by-using-sidepanel/vendor-form.tsx +108 -0
  125. package/templates/panels/vendor-example/by-using-sidepanel/vendor-types.ts +29 -0
  126. package/templates/select-dropdown/README.md +62 -0
  127. package/templates/select-dropdown/multiselect-input.tsx +2 -2
  128. package/templates/select-dropdown/select-input.tsx +2 -2
  129. package/templates/skeleton/README.md +53 -0
  130. package/templates/skeleton/index.ts +2 -0
  131. package/templates/skeleton/skeleton.css +36 -0
  132. package/templates/skeleton/skeleton.tsx +40 -0
  133. package/templates/skeleton/types.ts +12 -0
  134. package/templates/spinner/README.md +51 -0
  135. package/templates/spinner/index.ts +1 -0
  136. package/templates/spinner/spinner.css +58 -0
  137. package/templates/spinner/spinner.tsx +263 -0
  138. package/templates/toast/container.tsx +2 -2
  139. package/templates/utilities/formater.dateTime.md +74 -0
  140. package/templates/utilities/formater.dateTime.ts +310 -0
  141. package/templates/utilities/formater.phoneNumber.md +32 -0
  142. package/templates/utilities/formater.phoneNumber.ts +143 -0
  143. package/templates/utilities/sanitize.md +23 -0
  144. package/templates/utilities/sanitize.ts +148 -0
  145. /package/templates/form/{email-input.tsx → text-inputs/email-input.tsx} +0 -0
  146. /package/templates/form/{phone-input.tsx → text-inputs/phone-input.tsx} +0 -0
  147. /package/templates/form/{url-input.tsx → text-inputs/url-input.tsx} +0 -0
  148. /package/templates/{overlays → notes/under-dev/overlay}/portal.tsx +0 -0
@@ -0,0 +1,32 @@
1
+
2
+ ### Phone Number Formatter (`phone-number-formatter`)
3
+
4
+ - **Description**: Parses, validates, and formats phone numbers using `libphonenumber-js`. Supports national and international numbers, country-based parsing, country calling code prefixes, and graceful handling of invalid or placeholder values.
5
+
6
+ - **Exported Functions**:
7
+ - `setPhoneNumberFormat({ number, country, countryCode })`
8
+ - Formats valid phone numbers to their national format.
9
+ - Supports parsing using:
10
+ - Existing international numbers (`+1234567890`)
11
+ - Country calling codes (`+1`, `+91`, etc.)
12
+ - ISO country codes (`US`, `IN`, etc.)
13
+ - Returns `null` for:
14
+ - `null`
15
+ - `undefined`
16
+ - Empty strings
17
+ - Placeholder values such as `"null"`, `"undefined"`, and `"-"`
18
+ - Returns the original value when:
19
+ - The phone number is invalid
20
+ - Parsing fails
21
+ - Prioritizes parsing in the following order:
22
+ 1. Number already contains `+`
23
+ 2. `countryCode`
24
+ 3. `country`
25
+
26
+ - **Features**
27
+ - Supports both string and numeric inputs.
28
+ - Handles national and international phone numbers.
29
+ - Supports ISO country codes and country calling codes.
30
+ - Safely handles null, undefined, and placeholder values.
31
+ - Returns original input for invalid or unparsable numbers.
32
+ - Formats valid numbers using `formatNational()`.
@@ -0,0 +1,143 @@
1
+ import { parsePhoneNumberWithError, type CountryCode } from "libphonenumber-js";
2
+
3
+ /* ------------------------------------------------
4
+ ? Types & Interfaces
5
+ ------------------------------------------------*/
6
+ type PhoneFormatterArgs = {
7
+ number: string | number | null | undefined;
8
+ country?: CountryCode;
9
+ countryCode?: string; // +1, +91, etc.
10
+ };
11
+
12
+ /* ------------------------------------------------
13
+ ? Main function
14
+ @param- number: Phone number to be formatted
15
+ @param- country: Country code
16
+ @param- countryCode: Country calling code
17
+ @returns - Formatted phone number
18
+
19
+ *usage Type 1 (Use country code)
20
+
21
+ setPhoneNumberFormat({
22
+ number: "4165551234",
23
+ country: "US",
24
+ countryCode: "+1",
25
+ });
26
+
27
+ *useage Type 2 (Country code is provided)
28
+
29
+ setPhoneNumberFormat({
30
+ number: "4165551234",
31
+ countryCode: "+1",
32
+ });
33
+
34
+ *useage Type 3 (only country is provided)
35
+
36
+ setPhoneNumberFormat({
37
+ number: "4165551234",
38
+ country: "IN",
39
+ });
40
+
41
+ *useage Type 4 (Number already contains + ignore country code)
42
+
43
+ setPhoneNumberFormat({
44
+ number: "+14165551234",
45
+ country: "IN",
46
+ });
47
+
48
+
49
+
50
+ *useage Type 5 (Number already contains + so no need to provide country code)
51
+
52
+ setPhoneNumberFormat({
53
+ number: "+14165551234",
54
+ });
55
+
56
+ *usage Type 6 (null is provided)
57
+
58
+ setPhoneNumberFormat({
59
+ number: null,
60
+ });
61
+
62
+ *usage Type 7 (undefined is provided)
63
+
64
+ setPhoneNumberFormat({
65
+ number: undefined,
66
+ });
67
+
68
+
69
+ *usage Type 8 (placeholder value is provided)
70
+
71
+ setPhoneNumberFormat({
72
+ number: "-",
73
+ });
74
+
75
+ *usage Type 9 (invalid number)
76
+
77
+ setPhoneNumberFormat({
78
+ number: "abc",
79
+ });
80
+
81
+ *usage Type 10 (unformatted number)
82
+
83
+ setPhoneNumberFormat({
84
+ number: "1234",
85
+ });
86
+
87
+ ------------------------------------------------*/
88
+ export function setPhoneNumberFormat({
89
+ number,
90
+ country,
91
+ countryCode,
92
+ }: PhoneFormatterArgs): string | null {
93
+ // Handle nullish values
94
+ if (number == null) return null;
95
+ const strNum = String(number).trim();
96
+
97
+ // Handle common placeholder values
98
+ if (!strNum || ["null", "undefined", "-"].includes(strNum.toLowerCase())) {
99
+ return null;
100
+ }
101
+
102
+ try {
103
+ let phoneInput = strNum;
104
+
105
+ /**
106
+ * NOTE : Priority:
107
+ * 1. Number already contains '+'
108
+ * 2. countryCode
109
+ * 3. country
110
+ */
111
+
112
+ if (!phoneInput.startsWith("+") && countryCode) {
113
+ phoneInput = `${countryCode}${phoneInput}`;
114
+ }
115
+
116
+ const phone = phoneInput.startsWith("+")
117
+ ? parsePhoneNumberWithError(phoneInput)
118
+ : parsePhoneNumberWithError(phoneInput, country);
119
+
120
+ if (!phone.isValid()) {
121
+ return strNum;
122
+ }
123
+
124
+ return phone.formatNational();
125
+ } catch {
126
+ return strNum;
127
+ }
128
+ }
129
+
130
+ /*
131
+
132
+ *what number can handel as input
133
+
134
+ 1. null/undefined -> null
135
+ 2. "", "null", "-" -> null
136
+ 3. Number starts "+" -> parse as international
137
+ 4. countryCode -> prepend and parse
138
+ 5. country -> parse as national
139
+ 6. Valid number -> formatNational()
140
+ 7. Invalid number -> return original value
141
+ 8. Parse error -> return original value
142
+
143
+ */
@@ -0,0 +1,23 @@
1
+ ### Sanitize Data (`sanitize-fn`)
2
+
3
+ - **Description**: Recursively trims string values, nullifies empty strings, and checks for empty payloads in form data.
4
+
5
+ - **Exported Functions**:
6
+ - `sanitizeFormData({ data, skip, nullifyEmptyStrings })`
7
+ - Sanitizes an entire object and returns:
8
+ ```ts
9
+ {
10
+ isEmpty: boolean;
11
+ data: T;
12
+ }
13
+ ```
14
+ - Supports nested field exclusion using dot notation (e.g. `"user.email"`).
15
+ - Optionally preserves empty strings by setting `nullifyEmptyStrings` to `false`.
16
+
17
+ - **Features**
18
+ - Trims leading and trailing whitespace from strings.
19
+ - Converts empty strings to `null` (configurable).
20
+ - Supports nested objects and arrays.
21
+ - Supports skipping specific fields using dot notation.
22
+ - Preserves `Date` and `File` instances.
23
+ - Returns an `isEmpty` flag for quick form validation.
@@ -0,0 +1,148 @@
1
+ /* ------------------------------------------------
2
+ ? Types & Interfaces
3
+ ------------------------------------------------*/
4
+ type SanitizeFormDataOptions<T> = {
5
+ data: T;
6
+ skip?: string[];
7
+ nullifyEmptyStrings?: boolean;
8
+ };
9
+
10
+ type SanitizeFormDataResult<T> = {
11
+ isEmpty: boolean;
12
+ data: T;
13
+ };
14
+
15
+ /* ------------------------------------------------
16
+ ? Main function
17
+ @param - data: Object to be sanitized
18
+ @param - skip: Array of keys to skip
19
+ @param - nullifyEmptyStrings: Whether to nullify empty strings
20
+ @returns - Sanitized object
21
+
22
+ *usage Type 1
23
+
24
+ const {isEmpty,data:sanitizedData} = sanitizeFormData({data});
25
+
26
+ if(isEmpty){
27
+ return;
28
+ }
29
+
30
+ *usage Type 2
31
+ const {isEmpty,data:sanitizedData} = sanitizeFormData({data, skip:["password","user.email",]});
32
+
33
+ if(isEmpty){
34
+ return;
35
+ }
36
+
37
+ # NOTE : skip contains dot notation for nested objects and key names whose value will skip from sanitizing
38
+
39
+ *usage Type 3
40
+ const {isEmpty,data:sanitizedData} = sanitizeFormData({data, skip:["password","user.email",], nullifyEmptyStrings:false});
41
+
42
+ if(isEmpty){
43
+ return;
44
+ }
45
+
46
+
47
+ ------------------------------------------------*/
48
+ export const sanitizeFormData = <T>({
49
+ data,
50
+ skip = [],
51
+ nullifyEmptyStrings = true,
52
+ }: SanitizeFormDataOptions<T>): SanitizeFormDataResult<T> => {
53
+ const skipSet = new Set(skip);
54
+ const sanitizedData = sanitize(data, "", skipSet, nullifyEmptyStrings) as T;
55
+ return {
56
+ isEmpty: isEmptyValue(sanitizedData),
57
+ data: sanitizedData,
58
+ };
59
+ };
60
+
61
+ /* ------------------------------------------------
62
+ # ANCHOR : Helper Functions
63
+ ------------------------------------------------*/
64
+
65
+ /* ------------------------------------------------
66
+ ? Recursive Function
67
+ @param - value: Value to be sanitized
68
+ @param - path: Path of the value
69
+ @param - skipSet: Set of keys to skip
70
+ @param - nullifyEmptyStrings: Whether to nullify empty strings
71
+ @returns - Sanitized value
72
+ ------------------------------------------------*/
73
+ export function sanitize(
74
+ value: unknown,
75
+ path = "",
76
+ skipSet: Set<string>,
77
+ nullifyEmptyStrings: boolean,
78
+ ): unknown {
79
+ // Strings
80
+ if (typeof value === "string") {
81
+ if (skipSet.has(path)) {
82
+ return value;
83
+ }
84
+
85
+ const trimmed = value.trim();
86
+
87
+ return nullifyEmptyStrings && trimmed === "" ? null : trimmed;
88
+ }
89
+
90
+ // Arrays
91
+ if (Array.isArray(value)) {
92
+ return value.map((item, index) =>
93
+ sanitize(item, `${path}[${index}]`, skipSet, nullifyEmptyStrings),
94
+ );
95
+ }
96
+
97
+ // Plain Objects
98
+ if (
99
+ value &&
100
+ typeof value === "object" &&
101
+ !(value instanceof Date) &&
102
+ !(value instanceof File)
103
+ ) {
104
+ return Object.fromEntries(
105
+ Object.entries(value).map(([key, val]) => [
106
+ key,
107
+ sanitize(
108
+ val,
109
+ path ? `${path}.${key}` : key,
110
+ skipSet,
111
+ nullifyEmptyStrings,
112
+ ),
113
+ ]),
114
+ );
115
+ }
116
+
117
+ return value;
118
+ }
119
+
120
+ /* ------------------------------------------------
121
+ ? Check if value is empty
122
+ @param - value: Value to be checked
123
+ @returns - boolean
124
+ ------------------------------------------------*/
125
+ export function isEmptyValue(value: unknown): boolean {
126
+ if (value === null) return true;
127
+
128
+ if (typeof value === "string") {
129
+ return value.trim() === "";
130
+ }
131
+
132
+ if (Array.isArray(value)) {
133
+ return value.length === 0 || value.every(isEmptyValue);
134
+ }
135
+
136
+ if (
137
+ value &&
138
+ typeof value === "object" &&
139
+ !(value instanceof Date) &&
140
+ !(value instanceof File)
141
+ ) {
142
+ const values = Object.values(value);
143
+
144
+ return values.length === 0 || values.every(isEmptyValue);
145
+ }
146
+
147
+ return false;
148
+ }