@powerhousedao/design-system 1.39.12-dev.0 → 1.39.12-dev.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.
Files changed (33) hide show
  1. package/dist/src/scalars/components/fragments/id-autocomplete/id-autocomplete-list-option.js +1 -1
  2. package/dist/src/scalars/components/time-picker-field/time-picker-field-validations.d.ts.map +1 -1
  3. package/dist/src/scalars/components/time-picker-field/time-picker-field-validations.js +5 -1
  4. package/dist/src/ui/components/data-entry/time-picker/use-time-picker.d.ts.map +1 -1
  5. package/dist/src/ui/components/data-entry/time-picker/use-time-picker.js +3 -23
  6. package/dist/src/ui/components/data-entry/time-picker/utils.d.ts +12 -0
  7. package/dist/src/ui/components/data-entry/time-picker/utils.d.ts.map +1 -1
  8. package/dist/src/ui/components/data-entry/time-picker/utils.js +68 -5
  9. package/dist/src/ui/components/object-set-table/hooks/useGlobalTableKeyEvents.d.ts +3 -0
  10. package/dist/src/ui/components/object-set-table/hooks/useGlobalTableKeyEvents.d.ts.map +1 -0
  11. package/dist/src/ui/components/object-set-table/hooks/useGlobalTableKeyEvents.js +47 -0
  12. package/dist/src/ui/components/object-set-table/logic/selection-manager.d.ts +49 -0
  13. package/dist/src/ui/components/object-set-table/logic/selection-manager.d.ts.map +1 -0
  14. package/dist/src/ui/components/object-set-table/logic/selection-manager.js +96 -0
  15. package/dist/src/ui/components/object-set-table/logic/table-api.d.ts +52 -0
  16. package/dist/src/ui/components/object-set-table/logic/table-api.d.ts.map +1 -0
  17. package/dist/src/ui/components/object-set-table/logic/table-api.js +104 -0
  18. package/dist/src/ui/components/object-set-table/object-set-table.d.ts.map +1 -1
  19. package/dist/src/ui/components/object-set-table/object-set-table.js +11 -0
  20. package/dist/src/ui/components/object-set-table/subcomponents/body.d.ts.map +1 -1
  21. package/dist/src/ui/components/object-set-table/subcomponents/body.js +20 -15
  22. package/dist/src/ui/components/object-set-table/subcomponents/header/header-number-td.js +1 -1
  23. package/dist/src/ui/components/object-set-table/subcomponents/header.d.ts.map +1 -1
  24. package/dist/src/ui/components/object-set-table/subcomponents/header.js +3 -4
  25. package/dist/src/ui/components/object-set-table/subcomponents/table-focus-trap.d.ts.map +1 -1
  26. package/dist/src/ui/components/object-set-table/subcomponents/table-focus-trap.js +2 -2
  27. package/dist/src/ui/components/object-set-table/subcomponents/table-provider/table-provider.d.ts +2 -0
  28. package/dist/src/ui/components/object-set-table/subcomponents/table-provider/table-provider.d.ts.map +1 -1
  29. package/dist/src/ui/components/object-set-table/subcomponents/table-provider/table-provider.js +5 -69
  30. package/dist/src/ui/components/object-set-table/types.d.ts +22 -0
  31. package/dist/src/ui/components/object-set-table/types.d.ts.map +1 -1
  32. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  33. package/package.json +3 -3
@@ -39,7 +39,7 @@ const IdAutocompleteListOption = ({ variant = "withValue", icon, title = "Title
39
39
  typeof extraProps.agentType === "string" && (_jsx("div", { className: cn("flex max-w-full items-center justify-end"), children: _jsx("span", { className: cn("truncate text-xs leading-5", asPlaceholder
40
40
  ? "text-gray-400 dark:text-gray-700"
41
41
  : "text-gray-500 dark:text-gray-600"), children: extraProps.agentType }) }))] }));
42
- return (_jsxs("div", { className: cn("max-w-full rounded-md bg-transparent px-3 pb-2", variant === "withValue" ? "pt-2" : "pt-3", className), children: [variant === "withValue" && renderWithValue(), variant === "withValueAndTitle" &&
42
+ return (_jsxs("div", { className: cn("w-full max-w-full rounded-md bg-transparent px-3 pb-2", variant === "withValue" ? "pt-2" : "pt-3", className), children: [variant === "withValue" && renderWithValue(), variant === "withValueAndTitle" &&
43
43
  renderWithValueTitleAndDescription(false), variant === "withValueTitleAndDescription" &&
44
44
  renderWithValueTitleAndDescription()] }));
45
45
  };
@@ -1 +1 @@
1
- {"version":3,"file":"time-picker-field-validations.d.ts","sourceRoot":"","sources":["../../../../../src/scalars/components/time-picker-field/time-picker-field-validations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAQ/C,eAAO,MAAM,kBAAkB,GAC5B,gBAAgB,cAAc,MAC9B,OAAO,OAAO,kNA2Cd,CAAC"}
1
+ {"version":3,"file":"time-picker-field-validations.d.ts","sourceRoot":"","sources":["../../../../../src/scalars/components/time-picker-field/time-picker-field-validations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAU/C,eAAO,MAAM,kBAAkB,GAC5B,gBAAgB,cAAc,MAC9B,OAAO,OAAO,kNAgDd,CAAC"}
@@ -1,4 +1,4 @@
1
- import { convert24hTo12h, getTime, isFormatTimeAllowed, TIME_PATTERNS, } from "../../../ui/components/data-entry/time-picker/utils.js";
1
+ import { convert24hTo12h, getHoursAndMinutesFromValue, getTime, isFormatTimeAllowed, isValidTimeFromValue, TIME_PATTERNS, } from "../../../ui/components/data-entry/time-picker/utils.js";
2
2
  export const validateTimePicker = ({ timeFormat }) => (value) => {
3
3
  if (value === "") {
4
4
  return true;
@@ -6,6 +6,10 @@ export const validateTimePicker = ({ timeFormat }) => (value) => {
6
6
  if (value === undefined) {
7
7
  return true;
8
8
  }
9
+ const getHoursAndMinutes = getHoursAndMinutesFromValue(value);
10
+ if (!isValidTimeFromValue(getHoursAndMinutes)) {
11
+ return "Invalid time. Please enter time a valid format";
12
+ }
9
13
  // Validate the format of the value
10
14
  const time = getTime(value.trim());
11
15
  if (!timeFormat) {
@@ -1 +1 @@
1
- {"version":3,"file":"use-time-picker.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/components/data-entry/time-picker/use-time-picker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAiBjE,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,WAKtD,CAAC;AACF,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC5D,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,eAAO,MAAM,aAAa,GAAI,uHAU3B,oBAAoB;;;;;;;;;;2BA+BS,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC;;;;;;;;;oBAI1C,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC;;;;;;CAmK1D,CAAC"}
1
+ {"version":3,"file":"use-time-picker.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/components/data-entry/time-picker/use-time-picker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAiBjE,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,WAKtD,CAAC;AACF,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC5D,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,eAAO,MAAM,aAAa,GAAI,uHAU3B,oBAAoB;;;;;;;;;;2BA+BS,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC;;;;;;;;;oBAI1C,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC;;;;;;CAgJ1D,CAAC"}
@@ -31,30 +31,10 @@ export const useTimePicker = ({ value, defaultValue, onChange, onBlur, timeForma
31
31
  const input = e.target.value;
32
32
  // Get the period from the input if exists to avoid use the default period
33
33
  const inputPeriod = input.split(" ")[1];
34
- if (!isValidTimeInput(input)) {
35
- if (input === "") {
36
- setInputValue(input);
37
- onChange?.(createChangeEvent(""));
38
- onBlur?.(createBlurEvent(""));
39
- return;
40
- }
41
- // Create an empty but valid time value that matches the format expected by the value prop
42
- const inValid = formatInputsToValueFormat("", "", "±00:00");
43
- setInputValue(input);
44
- onChange?.(createChangeEvent(inValid));
45
- onBlur?.(createBlurEvent(input));
46
- return;
47
- }
48
34
  const validDisplay = formatInputToDisplayValid(input, is12HourFormat, timeIntervals, inputPeriod);
49
- // Check if the validDisplay is empty and if it is, set the inputValue to an empty string
50
- if (!validDisplay) {
51
- setInputValue("");
52
- onChange?.(createChangeEvent(""));
53
- onBlur?.(createBlurEvent(""));
54
- return;
55
- }
56
- setInputValue(validDisplay);
57
- const validValue = convert12hTo24h(validDisplay);
35
+ const valueForInput = isValidTimeInput(input) ? validDisplay : input;
36
+ setInputValue(valueForInput);
37
+ const validValue = convert12hTo24h(valueForInput);
58
38
  const { minutes, hours, period } = getHoursAndMinutes(validValue);
59
39
  const offsetUTC = getOffset(selectedTimeZone);
60
40
  if (is12HourFormat) {
@@ -192,4 +192,16 @@ export declare const getHoursAndMinutes: (input: string) => {
192
192
  period: string | undefined;
193
193
  };
194
194
  export declare const handleKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
195
+ /**
196
+ * Validates if a string has the hh:mm format and represents a valid time.
197
+ * @param {string} timeString - The string to validate.
198
+ * @returns {boolean} - Returns true if the string is valid, false otherwise.
199
+ */
200
+ export declare const isValidTimeFromValue: (timeString: string) => boolean;
201
+ /**
202
+ * Extracts hours and minutes from a time string value.
203
+ * @param {string} timeString - The time string to process.
204
+ * @returns {string} - Returns the time in hh:mm format if valid, empty string otherwise.
205
+ */
206
+ export declare const getHoursAndMinutesFromValue: (timeString: string) => string;
195
207
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/components/data-entry/time-picker/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,KACZ,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAYpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,UAAkC,CAAC;AACpE,eAAO,MAAM,mBAAmB,GAAI,QAAQ,MAAM,KAAG,OAEpD,CAAC;AACF,eAAO,MAAM,aAAa;IACxB,uEAAuE;;IAEvE,uEAAuE;;CAE/D,CAAC;AAEX,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,WAErC,CAAC;AACF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,WAM5C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,WAIpC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAa9D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,EACb,gBAAgB,OAAO,EACvB,iBAAY,EACZ,gBAAgB,UAAU,KACzB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CA2DrD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,OAmBhD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,WAOnD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,UAAU,GAAI,0BAAwB;;;GAWlD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM;;;;CAW9C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,MAAM,WAGzC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,WAAW,MAAM,WAG3C,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM,WAK9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,WAG1C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,WAAW,MAAM,KAAG,MAQ/C,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GACpC,OAAO,MAAM,EACb,SAAS,MAAM,EACf,gBAAgB,MAAM,KACrB,MAIF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,WAa5C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,yBAAyB,GACpC,OAAO,MAAM,EACb,gBAAgB,OAAO,EACvB,gBAAgB,MAAM,EACtB,gBAAgB,UAAU,WAY3B,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM;;;;CAO/C,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,GAAG,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,SA+BrE,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/components/data-entry/time-picker/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,KACZ,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAYpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,UAAkC,CAAC;AACpE,eAAO,MAAM,mBAAmB,GAAI,QAAQ,MAAM,KAAG,OAEpD,CAAC;AACF,eAAO,MAAM,aAAa;IACxB,uEAAuE;;IAEvE,uEAAuE;;CAE/D,CAAC;AAEX,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,WAErC,CAAC;AACF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,WAM5C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,WAIpC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAa9D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,EACb,gBAAgB,OAAO,EACvB,iBAAY,EACZ,gBAAgB,UAAU,KACzB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CA2DrD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,OAuChD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,WAOnD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,UAAU,GAAI,0BAAwB;;;GAWlD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM;;;;CAW9C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,MAAM,WAGzC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,WAAW,MAAM,WAG3C,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM,WAK9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,WAG1C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,WAAW,MAAM,KAAG,MAQ/C,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GACpC,OAAO,MAAM,EACb,SAAS,MAAM,EACf,gBAAgB,MAAM,KACrB,MAIF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,WAa5C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,yBAAyB,GACpC,OAAO,MAAM,EACb,gBAAgB,OAAO,EACvB,gBAAgB,MAAM,EACtB,gBAAgB,UAAU,WAY3B,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM;;;;CA4B/C,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,GAAG,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,SA+BrE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,YAAY,MAAM,YAItD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GAAI,YAAY,MAAM,WAI7D,CAAC"}
@@ -16,7 +16,7 @@ export const isFormatTimeAllowed = (format) => {
16
16
  };
17
17
  export const TIME_PATTERNS = {
18
18
  /** Matches times in 24-hour format (HH:mm) like: 0:00, 09:30, 23:59 */
19
- HOURS_24: /^([0-9]|0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])$/,
19
+ HOURS_24: /^([0-1][0-9]|2[0-3]):([0-5][0-9])$/,
20
20
  /** Matches times in 12-hour format (h:mm a) like: 1:00 AM, 12:59 PM */
21
21
  HOURS_12: /^(0?[1-9]|1[0-2]):([0-5][0-9])\s(AM|PM|am|pm)$/,
22
22
  };
@@ -150,7 +150,27 @@ export const isValidTimeInput = (input) => {
150
150
  input = input.trim();
151
151
  // Allow change the format and convert the time
152
152
  if (input.includes(":")) {
153
- return (TIME_PATTERNS.HOURS_12.test(input) || TIME_PATTERNS.HOURS_24.test(input));
153
+ // Must be exactly 5 characters for 24h format
154
+ if (input.length !== 5) {
155
+ return false;
156
+ }
157
+ // Split into hours and minutes
158
+ const [hours, minutes] = input.split(":");
159
+ // Hours and minutes must be numbers
160
+ const hoursNum = parseInt(hours, 10);
161
+ const minutesNum = parseInt(minutes, 10);
162
+ if (isNaN(hoursNum) || isNaN(minutesNum))
163
+ return false;
164
+ // Hours must be between 0 and 23
165
+ if (hoursNum < 0 || hoursNum > 23)
166
+ return false;
167
+ // Minutes must be between 0 and 59
168
+ if (minutesNum < 0 || minutesNum > 59)
169
+ return false;
170
+ // Minutes must be exactly 2 digits
171
+ if (minutes.length !== 2)
172
+ return false;
173
+ return true;
154
174
  }
155
175
  else {
156
176
  // "For digits, expect 3 or 4 characters and validate they're in range".
@@ -377,9 +397,32 @@ export const formatInputToDisplayValid = (input, is12HourFormat, timeIntervals,
377
397
  export const getHoursAndMinutes = (input) => {
378
398
  if (!input)
379
399
  return { hours: "", minutes: "", period: undefined };
380
- const [hours, minutes] = input.split(":");
381
- const period = input.includes("AM") || input.includes("PM") ? input.slice(-2) : undefined;
382
- return { hours, minutes, period };
400
+ if (input.includes(":")) {
401
+ const [hours, minutes] = input.split(":");
402
+ const period = input.includes("AM") || input.includes("PM")
403
+ ? input.slice(-2)
404
+ : undefined;
405
+ return { hours, minutes, period };
406
+ }
407
+ else {
408
+ // Handle short format (e.g., "1430" -> "14:30")
409
+ if (input.length === 3) {
410
+ return {
411
+ hours: input.slice(0, 1),
412
+ minutes: input.slice(1, 3),
413
+ period: undefined,
414
+ };
415
+ }
416
+ else if (input.length === 4) {
417
+ return {
418
+ hours: input.slice(0, 2),
419
+ minutes: input.slice(2, 4),
420
+ period: undefined,
421
+ };
422
+ }
423
+ // Return and invalid value as cannot be a value time
424
+ return { hours: "", minutes: "", period: undefined };
425
+ }
383
426
  };
384
427
  export const handleKeyDown = (e) => {
385
428
  // Allow control keys (backspace, delete, arrows, etc)
@@ -409,3 +452,23 @@ export const handleKeyDown = (e) => {
409
452
  }
410
453
  e.preventDefault();
411
454
  };
455
+ /**
456
+ * Validates if a string has the hh:mm format and represents a valid time.
457
+ * @param {string} timeString - The string to validate.
458
+ * @returns {boolean} - Returns true if the string is valid, false otherwise.
459
+ */
460
+ export const isValidTimeFromValue = (timeString) => {
461
+ // Regular expression to validate the hh:mm format
462
+ const regex = /^([01]?\d|2[0-3]):[0-5]\d$/;
463
+ return regex.test(timeString);
464
+ };
465
+ /**
466
+ * Extracts hours and minutes from a time string value.
467
+ * @param {string} timeString - The time string to process.
468
+ * @returns {string} - Returns the time in hh:mm format if valid, empty string otherwise.
469
+ */
470
+ export const getHoursAndMinutesFromValue = (timeString) => {
471
+ // Captures everything up to the second ':' regardless of the number of digits in the hour
472
+ const match = /^([^:]+:\d{2,})/.exec(timeString);
473
+ return match ? match[1] : "";
474
+ };
@@ -0,0 +1,3 @@
1
+ declare const useGlobalTableKeyEvents: () => void;
2
+ export { useGlobalTableKeyEvents };
3
+ //# sourceMappingURL=useGlobalTableKeyEvents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGlobalTableKeyEvents.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/components/object-set-table/hooks/useGlobalTableKeyEvents.tsx"],"names":[],"mappings":"AAIA,QAAA,MAAM,uBAAuB,YAmD5B,CAAC;AAEF,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { useEffect } from "react";
2
+ import { useInternalTableState } from "../subcomponents/table-provider/table-provider.js";
3
+ import { getDirectionFromKey, getNextSelectedCell } from "../utils.js";
4
+ const useGlobalTableKeyEvents = () => {
5
+ const { api } = useInternalTableState();
6
+ useEffect(() => {
7
+ const handleKeyDown = (e) => {
8
+ const isEditing = api.isEditing();
9
+ const selectedCell = api._getState().selectedCellIndex;
10
+ if (isEditing) {
11
+ if (e.key === "Enter") {
12
+ api.exitCellEditMode(true);
13
+ }
14
+ if (e.key === "Escape" && !!selectedCell) {
15
+ api.exitCellEditMode(false);
16
+ }
17
+ }
18
+ else {
19
+ if (e.key === "Enter" &&
20
+ !!selectedCell &&
21
+ api.canEditCell(selectedCell.row, selectedCell.column)) {
22
+ api.enterCellEditMode(selectedCell.row, selectedCell.column);
23
+ }
24
+ // arrow keys
25
+ if (["ArrowRight", "ArrowLeft", "ArrowDown", "ArrowUp", "Tab"].includes(e.key)) {
26
+ const direction = getDirectionFromKey(e.key);
27
+ const nextCell = getNextSelectedCell({
28
+ direction,
29
+ currentCell: selectedCell,
30
+ rowCount: api._getState().data.length,
31
+ columnCount: api._getConfig().columns.length,
32
+ moveToNextRow: e.key === "Tab",
33
+ });
34
+ if (e.key === "Tab") {
35
+ e.preventDefault();
36
+ }
37
+ api.selection.selectCell(nextCell.row, nextCell.column);
38
+ }
39
+ }
40
+ };
41
+ api._getTable()?.addEventListener("keydown", handleKeyDown);
42
+ return () => {
43
+ api._getTable()?.removeEventListener("keydown", handleKeyDown);
44
+ };
45
+ }, [api]);
46
+ };
47
+ export { useGlobalTableKeyEvents };
@@ -0,0 +1,49 @@
1
+ import type { TableApi } from "./table-api.js";
2
+ declare class SelectionManager<TData> {
3
+ private api;
4
+ constructor(api: TableApi<TData>);
5
+ /**
6
+ * Checks if the table allows row selection
7
+ */
8
+ canSelectRows(): boolean | undefined;
9
+ /**
10
+ * Checks if the table allows cell selection
11
+ */
12
+ canSelectCells(): boolean | undefined;
13
+ /**
14
+ * Clears the selection of the table
15
+ */
16
+ clear(): void;
17
+ /**
18
+ * Selects a single row in the table. Only one row can be selected at a time.
19
+ *
20
+ * @param rowIndex - The index of the row to select
21
+ */
22
+ selectRow(rowIndex: number): void;
23
+ /**
24
+ * Toggles the selection of a row in the table.
25
+ *
26
+ * @param rowIndex - The index of the row to toggle
27
+ */
28
+ toggleRow(rowIndex: number): void;
29
+ /**
30
+ * Selects a range of rows from the last active row to the given row index.
31
+ *
32
+ * @param rowIndex - The index of the row to select from
33
+ */
34
+ selectFromLastActiveRow(rowIndex: number): void;
35
+ /**
36
+ * Selects all rows in the table.
37
+ */
38
+ selectAllRows(): void;
39
+ toggleSelectAll(): void;
40
+ /**
41
+ * Selects a cell in the table.
42
+ *
43
+ * @param rowIndex - The index of the row to select
44
+ * @param columnIndex - The index of the column to select
45
+ */
46
+ selectCell(rowIndex: number, columnIndex: number): void;
47
+ }
48
+ export { SelectionManager };
49
+ //# sourceMappingURL=selection-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection-manager.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/components/object-set-table/logic/selection-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,cAAM,gBAAgB,CAAC,KAAK;IACd,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC;IAExC;;OAEG;IACH,aAAa;IAIb;;OAEG;IACH,cAAc;IAId;;OAEG;IACH,KAAK;IAIL;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM;IAS1B;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM;IAS1B;;;;OAIG;IACH,uBAAuB,CAAC,QAAQ,EAAE,MAAM;IASxC;;OAEG;IACH,aAAa;IASb,eAAe;IAQf;;;;;OAKG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAQjD;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,96 @@
1
+ class SelectionManager {
2
+ api;
3
+ constructor(api) {
4
+ this.api = api;
5
+ }
6
+ /**
7
+ * Checks if the table allows row selection
8
+ */
9
+ canSelectRows() {
10
+ return this.api._getConfig().allowRowSelection;
11
+ }
12
+ /**
13
+ * Checks if the table allows cell selection
14
+ */
15
+ canSelectCells() {
16
+ return this.api._getConfig().allowRowSelection;
17
+ }
18
+ /**
19
+ * Clears the selection of the table
20
+ */
21
+ clear() {
22
+ this.api._getState().dispatch?.({ type: "SELECT_CELL", payload: null });
23
+ }
24
+ /**
25
+ * Selects a single row in the table. Only one row can be selected at a time.
26
+ *
27
+ * @param rowIndex - The index of the row to select
28
+ */
29
+ selectRow(rowIndex) {
30
+ if (!this.canSelectRows())
31
+ return;
32
+ this.api._getState().dispatch?.({
33
+ type: "TOGGLE_SELECTED_ROW",
34
+ payload: { index: rowIndex, clearOtherSelections: true },
35
+ });
36
+ }
37
+ /**
38
+ * Toggles the selection of a row in the table.
39
+ *
40
+ * @param rowIndex - The index of the row to toggle
41
+ */
42
+ toggleRow(rowIndex) {
43
+ if (!this.canSelectRows())
44
+ return;
45
+ this.api._getState().dispatch?.({
46
+ type: "TOGGLE_SELECTED_ROW",
47
+ payload: { index: rowIndex },
48
+ });
49
+ }
50
+ /**
51
+ * Selects a range of rows from the last active row to the given row index.
52
+ *
53
+ * @param rowIndex - The index of the row to select from
54
+ */
55
+ selectFromLastActiveRow(rowIndex) {
56
+ if (!this.canSelectRows())
57
+ return;
58
+ this.api._getState().dispatch?.({
59
+ type: "SELECT_ROW_RANGE",
60
+ payload: rowIndex,
61
+ });
62
+ }
63
+ /**
64
+ * Selects all rows in the table.
65
+ */
66
+ selectAllRows() {
67
+ if (!this.canSelectRows())
68
+ return;
69
+ this.api._getState().dispatch?.({
70
+ type: "SELECT_ROW_RANGE",
71
+ payload: this.api._getState().data.length - 1,
72
+ });
73
+ }
74
+ toggleSelectAll() {
75
+ if (!this.canSelectRows())
76
+ return;
77
+ this.api._getState().dispatch?.({
78
+ type: "TOGGLE_SELECT_ALL_ROWS",
79
+ });
80
+ }
81
+ /**
82
+ * Selects a cell in the table.
83
+ *
84
+ * @param rowIndex - The index of the row to select
85
+ * @param columnIndex - The index of the column to select
86
+ */
87
+ selectCell(rowIndex, columnIndex) {
88
+ if (!this.canSelectCells())
89
+ return;
90
+ this.api._getState().dispatch?.({
91
+ type: "SELECT_CELL",
92
+ payload: { row: rowIndex, column: columnIndex },
93
+ });
94
+ }
95
+ }
96
+ export { SelectionManager };
@@ -0,0 +1,52 @@
1
+ import type { RefObject } from "react";
2
+ import type { TableState } from "../subcomponents/table-provider/table-reducer.js";
3
+ import type { CellContext, ObjectSetTableConfig } from "../types.js";
4
+ import { SelectionManager } from "./selection-manager.js";
5
+ declare class TableApi<TData> {
6
+ private readonly tableRef;
7
+ private readonly configRef;
8
+ private readonly stateRef;
9
+ readonly selection: SelectionManager<TData>;
10
+ constructor(tableRef: RefObject<HTMLTableElement>, configRef: RefObject<ObjectSetTableConfig<TData>>, stateRef: RefObject<TableState<TData>>);
11
+ _getTable(): HTMLTableElement | null;
12
+ _getConfig(): ObjectSetTableConfig<TData>;
13
+ _getState(): TableState<TData>;
14
+ _createCellContext(row: number, column: number): CellContext<TData>;
15
+ /**
16
+ * Checks if the cell at the given row and column can be edited
17
+ *
18
+ * @param row - The row index of the cell to check
19
+ * @param column - The column index of the cell to check
20
+ * @returns `true` if the cell can be edited, `false` otherwise
21
+ */
22
+ canEditCell(row: number, column: number): boolean | undefined;
23
+ /**
24
+ * Checks if the table is currently in cell edit mode
25
+ *
26
+ * @returns `true` if the table is in cell edit mode, `false` otherwise
27
+ */
28
+ isEditing(): boolean;
29
+ /**
30
+ * Checks if the table is currently in cell edit mode for the given cell
31
+ *
32
+ * @param row - The row index of the cell to check
33
+ * @param column - The column index of the cell to check
34
+ * @returns `true` if the table is in cell edit mode for the given cell, `false` otherwise
35
+ */
36
+ isEditingCell(row: number, column: number): boolean;
37
+ /**
38
+ * Enters cell edit mode for the given cell
39
+ *
40
+ * @param row - The row index of the cell to enter edit mode
41
+ * @param column - The column index of the cell to enter edit mode
42
+ */
43
+ enterCellEditMode(row: number, column: number): void;
44
+ /**
45
+ * Exits cell edit mode
46
+ *
47
+ * @param save - Whether to save the changes made in the cell
48
+ */
49
+ exitCellEditMode(save?: boolean): void;
50
+ }
51
+ export { TableApi };
52
+ //# sourceMappingURL=table-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-api.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/components/object-set-table/logic/table-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kDAAkD,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,cAAM,QAAQ,CAAC,KAAK;IAIhB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAL3B,SAAgB,SAAS,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;gBAGhC,QAAQ,EAAE,SAAS,CAAC,gBAAgB,CAAC,EACrC,SAAS,EAAE,SAAS,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,EACjD,QAAQ,EAAE,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAKzD,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAIpC,UAAU,IAAI,oBAAoB,CAAC,KAAK,CAAC;IAIzC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IAI9B,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC;IAWnE;;;;;;OAMG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAIvC;;;;OAIG;IACH,SAAS;IAIT;;;;;;OAMG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAQzC;;;;;OAKG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAS7C;;;;OAIG;IACH,gBAAgB,CAAC,IAAI,UAAO;CAgC7B;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,104 @@
1
+ import { getNextSelectedCell } from "../utils.js";
2
+ import { SelectionManager } from "./selection-manager.js";
3
+ class TableApi {
4
+ tableRef;
5
+ configRef;
6
+ stateRef;
7
+ selection;
8
+ constructor(tableRef, configRef, stateRef) {
9
+ this.tableRef = tableRef;
10
+ this.configRef = configRef;
11
+ this.stateRef = stateRef;
12
+ this.selection = new SelectionManager(this);
13
+ }
14
+ _getTable() {
15
+ return this.tableRef.current;
16
+ }
17
+ _getConfig() {
18
+ return this.configRef.current;
19
+ }
20
+ _getState() {
21
+ return this.stateRef.current;
22
+ }
23
+ _createCellContext(row, column) {
24
+ return {
25
+ row: this._getState().data[row],
26
+ column: this._getConfig().columns[column],
27
+ rowIndex: row,
28
+ columnIndex: column,
29
+ tableConfig: this._getConfig(),
30
+ };
31
+ }
32
+ // cell editing
33
+ /**
34
+ * Checks if the cell at the given row and column can be edited
35
+ *
36
+ * @param row - The row index of the cell to check
37
+ * @param column - The column index of the cell to check
38
+ * @returns `true` if the cell can be edited, `false` otherwise
39
+ */
40
+ canEditCell(row, column) {
41
+ return this._getConfig().columns[column].editable;
42
+ }
43
+ /**
44
+ * Checks if the table is currently in cell edit mode
45
+ *
46
+ * @returns `true` if the table is in cell edit mode, `false` otherwise
47
+ */
48
+ isEditing() {
49
+ return this._getState().isCellEditMode;
50
+ }
51
+ /**
52
+ * Checks if the table is currently in cell edit mode for the given cell
53
+ *
54
+ * @param row - The row index of the cell to check
55
+ * @param column - The column index of the cell to check
56
+ * @returns `true` if the table is in cell edit mode for the given cell, `false` otherwise
57
+ */
58
+ isEditingCell(row, column) {
59
+ return (this._getState().isCellEditMode &&
60
+ this._getState().selectedCellIndex?.row === row &&
61
+ this._getState().selectedCellIndex?.column === column);
62
+ }
63
+ /**
64
+ * Enters cell edit mode for the given cell
65
+ *
66
+ * @param row - The row index of the cell to enter edit mode
67
+ * @param column - The column index of the cell to enter edit mode
68
+ */
69
+ enterCellEditMode(row, column) {
70
+ if (!this.canEditCell(row, column))
71
+ throw new Error("Cell is not editable");
72
+ this._getState().dispatch?.({
73
+ type: "ENTER_CELL_EDIT_MODE",
74
+ payload: { row, column },
75
+ });
76
+ }
77
+ /**
78
+ * Exits cell edit mode
79
+ *
80
+ * @param save - Whether to save the changes made in the cell
81
+ */
82
+ exitCellEditMode(save = true) {
83
+ // TODO: before exiting, check if the ${value} edited is valid
84
+ // exit edit mode
85
+ const selectedCell = this._getState().selectedCellIndex ?? {
86
+ row: 0,
87
+ column: 0,
88
+ };
89
+ this.selection.selectCell(selectedCell.row, selectedCell.column);
90
+ if (save) {
91
+ const value = this._getConfig().columns[selectedCell.column]?.valueGetter?.(this._getState().data[selectedCell.row], this._createCellContext(selectedCell.row, selectedCell.column));
92
+ this._getConfig().columns[selectedCell.column]?.onSave?.(`${value} edited`, this._createCellContext(selectedCell.row, selectedCell.column));
93
+ const nextCell = getNextSelectedCell({
94
+ direction: "down",
95
+ currentCell: selectedCell,
96
+ rowCount: this._getState().data.length,
97
+ columnCount: this._getConfig().columns.length,
98
+ moveToNextRow: true,
99
+ });
100
+ this.selection.selectCell(nextCell.row, nextCell.column);
101
+ }
102
+ }
103
+ }
104
+ export { TableApi };
@@ -1 +1 @@
1
- {"version":3,"file":"object-set-table.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/object-set-table/object-set-table.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEjE;;;;;;;GAOG;AACH,QAAA,MAAM,cAAc,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAAE,eAEpD,oBAAoB,CAAC,CAAC,CAAC,4CAsCzB,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"object-set-table.d.ts","sourceRoot":"","sources":["../../../../../src/ui/components/object-set-table/object-set-table.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEjE;;;;;;;GAOG;AACH,QAAA,MAAM,cAAc,GAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAAE,eAEpD,oBAAoB,CAAC,CAAC,CAAC,4CAkDzB,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -29,6 +29,17 @@ const ObjectSetTable = ({ ...config }) => {
29
29
  valueGetter: column.valueGetter ?? defaultValueGetter,
30
30
  valueFormatter: column.valueFormatter ?? defaultValueFormatter,
31
31
  renderCell: column.renderCell ?? getRenderFn(column.type),
32
+ editable: column.editable ?? false,
33
+ // TODO: move the default onSave to a utility function
34
+ onSave: column.onSave ??
35
+ ((value, context) => {
36
+ // TODO: fix this
37
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
38
+ // @ts-expect-error
39
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
40
+ config.data[context.rowIndex][context.column.field] = value;
41
+ return true;
42
+ }),
32
43
  })),
33
44
  allowRowSelection: config.allowRowSelection ?? true,
34
45
  showRowNumbers: config.showRowNumbers ?? true,
@@ -1 +1 @@
1
- {"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/components/object-set-table/subcomponents/body.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQpE,UAAU,cAAc,CAAC,CAAC,SAAS,QAAQ;IACzC,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;CACzB;AAED,QAAA,MAAM,SAAS,GAAI,CAAC,SAAS,QAAQ,EAAE,oBAGpC,cAAc,CAAC,CAAC,CAAC,4CAuKnB,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/components/object-set-table/subcomponents/body.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAe,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQpE,UAAU,cAAc,CAAC,CAAC,SAAS,QAAQ;IACzC,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;CACzB;AAED,QAAA,MAAM,SAAS,GAAI,CAAC,SAAS,QAAQ,EAAE,oBAGpC,cAAc,CAAC,CAAC,CAAC,4CAgLnB,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC"}