@seamapi/react 4.6.0 → 4.7.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 (80) hide show
  1. package/README.md +2 -2
  2. package/dist/elements.js +11530 -9343
  3. package/dist/elements.js.map +1 -1
  4. package/dist/index.css +255 -3
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.min.css +1 -1
  7. package/dist/index.min.css.map +1 -1
  8. package/lib/icons/Trash.d.ts +2 -0
  9. package/lib/icons/Trash.js +5 -0
  10. package/lib/icons/Trash.js.map +1 -0
  11. package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js +17 -1
  12. package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js.map +1 -1
  13. package/lib/seam/thermostats/thermostat-device.d.ts +2 -1
  14. package/lib/seam/thermostats/thermostat-device.js.map +1 -1
  15. package/lib/seam/thermostats/unit-conversion.d.ts +5 -2
  16. package/lib/seam/thermostats/unit-conversion.js +5 -2
  17. package/lib/seam/thermostats/unit-conversion.js.map +1 -1
  18. package/lib/seam/thermostats/use-create-thermostat-climate-preset.d.ts +6 -0
  19. package/lib/seam/thermostats/use-create-thermostat-climate-preset.js +55 -0
  20. package/lib/seam/thermostats/use-create-thermostat-climate-preset.js.map +1 -0
  21. package/lib/seam/thermostats/use-delete-thermostat-climate-preset.d.ts +6 -0
  22. package/lib/seam/thermostats/use-delete-thermostat-climate-preset.js +44 -0
  23. package/lib/seam/thermostats/use-delete-thermostat-climate-preset.js.map +1 -0
  24. package/lib/seam/thermostats/use-update-thermostat-climate-preset.d.ts +6 -0
  25. package/lib/seam/thermostats/use-update-thermostat-climate-preset.js +55 -0
  26. package/lib/seam/thermostats/use-update-thermostat-climate-preset.js.map +1 -0
  27. package/lib/ui/Button.d.ts +3 -2
  28. package/lib/ui/Button.js +12 -4
  29. package/lib/ui/Button.js.map +1 -1
  30. package/lib/ui/IconButton.d.ts +5 -2
  31. package/lib/ui/IconButton.js +2 -2
  32. package/lib/ui/IconButton.js.map +1 -1
  33. package/lib/ui/Popover/Popover.d.ts +17 -0
  34. package/lib/ui/Popover/Popover.js +85 -0
  35. package/lib/ui/Popover/Popover.js.map +1 -0
  36. package/lib/ui/Popover/PopoverContentPrompt.d.ts +11 -0
  37. package/lib/ui/Popover/PopoverContentPrompt.js +12 -0
  38. package/lib/ui/Popover/PopoverContentPrompt.js.map +1 -0
  39. package/lib/ui/thermostat/ClimateModeMenu.d.ts +7 -2
  40. package/lib/ui/thermostat/ClimateModeMenu.js +7 -2
  41. package/lib/ui/thermostat/ClimateModeMenu.js.map +1 -1
  42. package/lib/ui/thermostat/ClimatePreset.d.ts +8 -0
  43. package/lib/ui/thermostat/ClimatePreset.js +141 -0
  44. package/lib/ui/thermostat/ClimatePreset.js.map +1 -0
  45. package/lib/ui/thermostat/ClimatePresets.d.ts +9 -0
  46. package/lib/ui/thermostat/ClimatePresets.js +72 -0
  47. package/lib/ui/thermostat/ClimatePresets.js.map +1 -0
  48. package/lib/ui/thermostat/FanModeMenu.d.ts +3 -1
  49. package/lib/ui/thermostat/FanModeMenu.js +5 -2
  50. package/lib/ui/thermostat/FanModeMenu.js.map +1 -1
  51. package/lib/ui/thermostat/ThermostatCard.d.ts +1 -0
  52. package/lib/ui/thermostat/ThermostatCard.js +4 -2
  53. package/lib/ui/thermostat/ThermostatCard.js.map +1 -1
  54. package/lib/ui/types.d.ts +3 -3
  55. package/lib/version.d.ts +1 -1
  56. package/lib/version.js +1 -1
  57. package/package.json +3 -2
  58. package/src/lib/icons/Trash.tsx +28 -0
  59. package/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx +52 -1
  60. package/src/lib/seam/thermostats/thermostat-device.ts +4 -0
  61. package/src/lib/seam/thermostats/unit-conversion.ts +12 -2
  62. package/src/lib/seam/thermostats/use-create-thermostat-climate-preset.ts +101 -0
  63. package/src/lib/seam/thermostats/use-delete-thermostat-climate-preset.ts +84 -0
  64. package/src/lib/seam/thermostats/use-update-thermostat-climate-preset.ts +103 -0
  65. package/src/lib/ui/Button.tsx +20 -3
  66. package/src/lib/ui/IconButton.tsx +19 -2
  67. package/src/lib/ui/Popover/Popover.tsx +168 -0
  68. package/src/lib/ui/Popover/PopoverContentPrompt.tsx +58 -0
  69. package/src/lib/ui/thermostat/ClimateModeMenu.tsx +33 -1
  70. package/src/lib/ui/thermostat/ClimatePreset.tsx +373 -0
  71. package/src/lib/ui/thermostat/ClimatePresets.tsx +235 -0
  72. package/src/lib/ui/thermostat/FanModeMenu.tsx +20 -2
  73. package/src/lib/ui/thermostat/ThermostatCard.tsx +10 -4
  74. package/src/lib/ui/types.ts +3 -3
  75. package/src/lib/version.ts +1 -1
  76. package/src/styles/_buttons.scss +56 -2
  77. package/src/styles/_main.scss +2 -0
  78. package/src/styles/_popover.scss +46 -0
  79. package/src/styles/_spinner.scss +1 -1
  80. package/src/styles/_thermostat.scss +154 -2
@@ -0,0 +1,6 @@
1
+ import type { SeamHttpApiError, ThermostatsCreateClimatePresetBody } from '@seamapi/http/connect';
2
+ import { type UseMutationResult } from '@tanstack/react-query';
3
+ export type UseCreateThermostatClimatePresetParams = never;
4
+ export type UseCreateThermostatClimatePresetData = undefined;
5
+ export type UseCreateThermostatClimatePresetVariables = ThermostatsCreateClimatePresetBody;
6
+ export declare function useCreateThermostatClimatePreset(): UseMutationResult<UseCreateThermostatClimatePresetData, SeamHttpApiError, UseCreateThermostatClimatePresetVariables>;
@@ -0,0 +1,55 @@
1
+ import { useMutation, useQueryClient, } from '@tanstack/react-query';
2
+ import { fahrenheitToCelsius } from '../../../lib/seam/thermostats/unit-conversion.js';
3
+ import { NullSeamClientError, useSeamClient } from '../../../lib/seam/use-seam-client.js';
4
+ export function useCreateThermostatClimatePreset() {
5
+ const { client } = useSeamClient();
6
+ const queryClient = useQueryClient();
7
+ return useMutation({
8
+ mutationFn: async (variables) => {
9
+ if (client === null)
10
+ throw new NullSeamClientError();
11
+ await client.thermostats.createClimatePreset(variables);
12
+ },
13
+ onSuccess: (_data, variables) => {
14
+ queryClient.setQueryData(['devices', 'get', { device_id: variables.device_id }], (device) => {
15
+ if (device == null) {
16
+ return;
17
+ }
18
+ return getUpdatedDevice(device, variables);
19
+ });
20
+ queryClient.setQueryData(['devices', 'list', { device_id: variables.device_id }], (devices) => {
21
+ if (devices == null) {
22
+ return [];
23
+ }
24
+ return devices.map((device) => {
25
+ if (device.device_id === variables.device_id) {
26
+ return getUpdatedDevice(device, variables);
27
+ }
28
+ return device;
29
+ });
30
+ });
31
+ },
32
+ });
33
+ }
34
+ const getUpdatedDevice = (device, variables) => {
35
+ const preset = {
36
+ ...variables,
37
+ cooling_set_point_celsius: fahrenheitToCelsius(variables.cooling_set_point_fahrenheit),
38
+ heating_set_point_celsius: fahrenheitToCelsius(variables.heating_set_point_fahrenheit),
39
+ display_name: variables.name ?? variables.climate_preset_key,
40
+ can_delete: true,
41
+ can_edit: true,
42
+ manual_override_allowed: false,
43
+ };
44
+ return {
45
+ ...device,
46
+ properties: {
47
+ ...device.properties,
48
+ available_climate_presets: [
49
+ preset,
50
+ ...(device.properties.available_climate_presets ?? []),
51
+ ],
52
+ },
53
+ };
54
+ };
55
+ //# sourceMappingURL=use-create-thermostat-climate-preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-create-thermostat-climate-preset.js","sourceRoot":"","sources":["../../../src/lib/seam/thermostats/use-create-thermostat-climate-preset.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,WAAW,EAEX,cAAc,GACf,MAAM,uBAAuB,CAAA;AAM9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAC7E,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAQhF,MAAM,UAAU,gCAAgC;IAK9C,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IAEpC,OAAO,WAAW,CAIhB;QACA,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;YAC9B,IAAI,MAAM,KAAK,IAAI;gBAAE,MAAM,IAAI,mBAAmB,EAAE,CAAA;YACpD,MAAM,MAAM,CAAC,WAAW,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAA;QACzD,CAAC;QACD,SAAS,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YAC9B,WAAW,CAAC,YAAY,CACtB,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,EACtD,CAAC,MAAM,EAAE,EAAE;gBACT,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;oBACnB,OAAM;gBACR,CAAC;gBAED,OAAO,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;YAC5C,CAAC,CACF,CAAA;YAED,WAAW,CAAC,YAAY,CACtB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,EACvD,CAAC,OAAO,EAAsB,EAAE;gBAC9B,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;oBACpB,OAAO,EAAE,CAAA;gBACX,CAAC;gBAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;oBAC5B,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,SAAS,EAAE,CAAC;wBAC7C,OAAO,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;oBAC5C,CAAC;oBAED,OAAO,MAAM,CAAA;gBACf,CAAC,CAAC,CAAA;YACJ,CAAC,CACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,gBAAgB,GAAG,CACvB,MAAwB,EACxB,SAAoD,EAClC,EAAE;IACpB,MAAM,MAAM,GAA4B;QACtC,GAAG,SAAS;QACZ,yBAAyB,EAAE,mBAAmB,CAC5C,SAAS,CAAC,4BAA4B,CACvC;QACD,yBAAyB,EAAE,mBAAmB,CAC5C,SAAS,CAAC,4BAA4B,CACvC;QACD,YAAY,EAAE,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,kBAAkB;QAC5D,UAAU,EAAE,IAAI;QAChB,QAAQ,EAAE,IAAI;QACd,uBAAuB,EAAE,KAAK;KAC/B,CAAA;IAED,OAAO;QACL,GAAG,MAAM;QACT,UAAU,EAAE;YACV,GAAG,MAAM,CAAC,UAAU;YACpB,yBAAyB,EAAE;gBACzB,MAAM;gBACN,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,yBAAyB,IAAI,EAAE,CAAC;aACvD;SACF;KACF,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { SeamHttpApiError, ThermostatsDeleteClimatePresetBody } from '@seamapi/http/connect';
2
+ import { type UseMutationResult } from '@tanstack/react-query';
3
+ export type UseDeleteThermostatClimatePresetParams = never;
4
+ export type UseDeleteThermostatClimatePresetData = undefined;
5
+ export type UseDeleteThermostatClimatePresetVariables = ThermostatsDeleteClimatePresetBody;
6
+ export declare function useDeleteThermostatClimatePreset(): UseMutationResult<UseDeleteThermostatClimatePresetData, SeamHttpApiError, UseDeleteThermostatClimatePresetVariables>;
@@ -0,0 +1,44 @@
1
+ import { useMutation, useQueryClient, } from '@tanstack/react-query';
2
+ import { NullSeamClientError, useSeamClient } from '../../../lib/seam/use-seam-client.js';
3
+ export function useDeleteThermostatClimatePreset() {
4
+ const { client } = useSeamClient();
5
+ const queryClient = useQueryClient();
6
+ return useMutation({
7
+ mutationFn: async (variables) => {
8
+ if (client === null)
9
+ throw new NullSeamClientError();
10
+ await client.thermostats.deleteClimatePreset(variables);
11
+ },
12
+ onSuccess: (_data, variables) => {
13
+ queryClient.setQueryData(['devices', 'get', { device_id: variables.device_id }], (device) => {
14
+ if (device == null) {
15
+ return;
16
+ }
17
+ return getUpdatedDevice(device, variables);
18
+ });
19
+ queryClient.setQueryData(['devices', 'list', { device_id: variables.device_id }], (devices) => {
20
+ if (devices == null) {
21
+ return [];
22
+ }
23
+ return devices.map((device) => {
24
+ if (device.device_id === variables.device_id) {
25
+ return getUpdatedDevice(device, variables);
26
+ }
27
+ return device;
28
+ });
29
+ });
30
+ },
31
+ });
32
+ }
33
+ function getUpdatedDevice(device, variables) {
34
+ return {
35
+ ...device,
36
+ properties: {
37
+ ...device.properties,
38
+ available_climate_presets: device.properties.available_climate_presets.filter((preset) => {
39
+ return preset.climate_preset_key !== variables.climate_preset_key;
40
+ }),
41
+ },
42
+ };
43
+ }
44
+ //# sourceMappingURL=use-delete-thermostat-climate-preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-delete-thermostat-climate-preset.js","sourceRoot":"","sources":["../../../src/lib/seam/thermostats/use-delete-thermostat-climate-preset.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,WAAW,EAEX,cAAc,GACf,MAAM,uBAAuB,CAAA;AAG9B,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAShF,MAAM,UAAU,gCAAgC;IAK9C,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IAEpC,OAAO,WAAW,CAIhB;QACA,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;YAC9B,IAAI,MAAM,KAAK,IAAI;gBAAE,MAAM,IAAI,mBAAmB,EAAE,CAAA;YACpD,MAAM,MAAM,CAAC,WAAW,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAA;QACzD,CAAC;QACD,SAAS,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YAC9B,WAAW,CAAC,YAAY,CACtB,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,EACtD,CAAC,MAAM,EAAE,EAAE;gBACT,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;oBACnB,OAAM;gBACR,CAAC;gBAED,OAAO,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;YAC5C,CAAC,CACF,CAAA;YAED,WAAW,CAAC,YAAY,CACtB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,EACvD,CAAC,OAAO,EAAsB,EAAE;gBAC9B,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;oBACpB,OAAO,EAAE,CAAA;gBACX,CAAC;gBAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;oBAC5B,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,SAAS,EAAE,CAAC;wBAC7C,OAAO,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;oBAC5C,CAAC;oBAED,OAAO,MAAM,CAAA;gBACf,CAAC,CAAC,CAAA;YACJ,CAAC,CACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,MAAwB,EACxB,SAAoD;IAEpD,OAAO;QACL,GAAG,MAAM;QACT,UAAU,EAAE;YACV,GAAG,MAAM,CAAC,UAAU;YACpB,yBAAyB,EACvB,MAAM,CAAC,UAAU,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE;gBAC5D,OAAO,MAAM,CAAC,kBAAkB,KAAK,SAAS,CAAC,kBAAkB,CAAA;YACnE,CAAC,CAAC;SACL;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { SeamHttpApiError, ThermostatsUpdateClimatePresetBody } from '@seamapi/http/connect';
2
+ import { type UseMutationResult } from '@tanstack/react-query';
3
+ export type UseUpdateThermostatClimatePresetParams = never;
4
+ export type UseUpdateThermostatClimatePresetData = undefined;
5
+ export type UseUpdateThermostatClimatePresetVariables = Omit<ThermostatsUpdateClimatePresetBody, 'manual_override_allowed'>;
6
+ export declare function useUpdateThermostatClimatePreset(): UseMutationResult<UseUpdateThermostatClimatePresetData, SeamHttpApiError, UseUpdateThermostatClimatePresetVariables>;
@@ -0,0 +1,55 @@
1
+ import { useMutation, useQueryClient, } from '@tanstack/react-query';
2
+ import { fahrenheitToCelsius } from '../../../lib/seam/thermostats/unit-conversion.js';
3
+ import { NullSeamClientError, useSeamClient } from '../../../lib/seam/use-seam-client.js';
4
+ export function useUpdateThermostatClimatePreset() {
5
+ const { client } = useSeamClient();
6
+ const queryClient = useQueryClient();
7
+ return useMutation({
8
+ mutationFn: async (variables) => {
9
+ if (client === null)
10
+ throw new NullSeamClientError();
11
+ await client.thermostats.createClimatePreset(variables);
12
+ },
13
+ onSuccess: (_data, variables) => {
14
+ queryClient.setQueryData(['devices', 'get', { device_id: variables.device_id }], (device) => {
15
+ if (device == null) {
16
+ return;
17
+ }
18
+ return getUpdatedDevice(device, variables);
19
+ });
20
+ queryClient.setQueryData(['devices', 'list', { device_id: variables.device_id }], (devices) => {
21
+ if (devices == null) {
22
+ return [];
23
+ }
24
+ return devices.map((device) => {
25
+ if (device.device_id === variables.device_id) {
26
+ return getUpdatedDevice(device, variables);
27
+ }
28
+ return device;
29
+ });
30
+ });
31
+ },
32
+ });
33
+ }
34
+ function getUpdatedDevice(device, variables) {
35
+ const preset = {
36
+ ...variables,
37
+ cooling_set_point_celsius: fahrenheitToCelsius(variables.cooling_set_point_fahrenheit),
38
+ heating_set_point_celsius: fahrenheitToCelsius(variables.heating_set_point_fahrenheit),
39
+ display_name: variables.name ?? variables.climate_preset_key,
40
+ can_delete: true,
41
+ can_edit: true,
42
+ manual_override_allowed: true,
43
+ };
44
+ return {
45
+ ...device,
46
+ properties: {
47
+ ...device.properties,
48
+ available_climate_presets: [
49
+ preset,
50
+ ...(device.properties.available_climate_presets ?? []),
51
+ ],
52
+ },
53
+ };
54
+ }
55
+ //# sourceMappingURL=use-update-thermostat-climate-preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-update-thermostat-climate-preset.js","sourceRoot":"","sources":["../../../src/lib/seam/thermostats/use-update-thermostat-climate-preset.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,WAAW,EAEX,cAAc,GACf,MAAM,uBAAuB,CAAA;AAM9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAC7E,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAUhF,MAAM,UAAU,gCAAgC;IAK9C,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IAEpC,OAAO,WAAW,CAIhB;QACA,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;YAC9B,IAAI,MAAM,KAAK,IAAI;gBAAE,MAAM,IAAI,mBAAmB,EAAE,CAAA;YACpD,MAAM,MAAM,CAAC,WAAW,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAA;QACzD,CAAC;QACD,SAAS,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YAC9B,WAAW,CAAC,YAAY,CACtB,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,EACtD,CAAC,MAAM,EAAE,EAAE;gBACT,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;oBACnB,OAAM;gBACR,CAAC;gBAED,OAAO,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;YAC5C,CAAC,CACF,CAAA;YAED,WAAW,CAAC,YAAY,CACtB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,EACvD,CAAC,OAAO,EAAsB,EAAE;gBAC9B,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;oBACpB,OAAO,EAAE,CAAA;gBACX,CAAC;gBAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;oBAC5B,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,SAAS,EAAE,CAAC;wBAC7C,OAAO,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;oBAC5C,CAAC;oBAED,OAAO,MAAM,CAAA;gBACf,CAAC,CAAC,CAAA;YACJ,CAAC,CACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,MAAwB,EACxB,SAAoD;IAEpD,MAAM,MAAM,GAA4B;QACtC,GAAG,SAAS;QACZ,yBAAyB,EAAE,mBAAmB,CAC5C,SAAS,CAAC,4BAA4B,CACvC;QACD,yBAAyB,EAAE,mBAAmB,CAC5C,SAAS,CAAC,4BAA4B,CACvC;QACD,YAAY,EAAE,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,kBAAkB;QAC5D,UAAU,EAAE,IAAI;QAChB,QAAQ,EAAE,IAAI;QACd,uBAAuB,EAAE,IAAI;KAC9B,CAAA;IAED,OAAO;QACL,GAAG,MAAM;QACT,UAAU,EAAE;YACV,GAAG,MAAM,CAAC,UAAU;YACpB,yBAAyB,EAAE;gBACzB,MAAM;gBACN,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,yBAAyB,IAAI,EAAE,CAAC;aACvD;SACF;KACF,CAAA;AACH,CAAC"}
@@ -1,12 +1,13 @@
1
1
  import type { MouseEventHandler, PropsWithChildren } from 'react';
2
2
  interface ButtonProps extends PropsWithChildren {
3
- variant?: 'solid' | 'outline' | 'neutral';
3
+ variant?: 'solid' | 'outline' | 'neutral' | 'danger';
4
4
  size?: 'small' | 'medium' | 'large';
5
5
  type?: 'button' | 'submit';
6
6
  disabled?: boolean;
7
7
  onClick?: MouseEventHandler<HTMLButtonElement>;
8
8
  className?: string;
9
9
  onMouseDown?: MouseEventHandler<HTMLButtonElement>;
10
+ loading?: boolean;
10
11
  }
11
- export declare function Button({ variant, children, size, disabled, onClick, className, onMouseDown, type, }: ButtonProps): JSX.Element;
12
+ export declare function Button({ variant, children, size, disabled, onClick, className, onMouseDown, type, loading, }: ButtonProps): JSX.Element;
12
13
  export {};
package/lib/ui/Button.js CHANGED
@@ -1,8 +1,16 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import classNames from 'classnames';
3
- export function Button({ variant = 'outline', children, size = 'medium', disabled = false, onClick, className, onMouseDown, type = 'button', }) {
4
- return (_jsx("button", { className: classNames(`seam-btn seam-btn-${variant} seam-btn-${size}`, {
3
+ import { Spinner } from '../../lib/ui/Spinner/Spinner.js';
4
+ export function Button({ variant = 'outline', children, size = 'medium', disabled = false, onClick, className, onMouseDown, type = 'button', loading = false, }) {
5
+ return (_jsxs("button", { className: classNames(`seam-btn seam-btn-${variant} seam-btn-${size}`, {
5
6
  'seam-btn-disabled': disabled,
6
- }, className), disabled: disabled, onClick: onClick, onMouseDown: onMouseDown, type: type, children: children }));
7
+ 'seam-btn-loading': loading,
8
+ }, className), disabled: disabled, onClick: (e) => {
9
+ if (loading || disabled) {
10
+ e.preventDefault();
11
+ return;
12
+ }
13
+ onClick?.(e);
14
+ }, onMouseDown: onMouseDown, type: type, children: [_jsx("span", { className: 'seam-btn-content', children: children }), loading && (_jsx("div", { className: 'seam-btn-loading', children: _jsx(Spinner, { size: 'small' }) }))] }));
7
15
  }
8
16
  //# sourceMappingURL=Button.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/lib/ui/Button.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAanC,MAAM,UAAU,MAAM,CAAC,EACrB,OAAO,GAAG,SAAS,EACnB,QAAQ,EACR,IAAI,GAAG,QAAQ,EACf,QAAQ,GAAG,KAAK,EAChB,OAAO,EACP,SAAS,EACT,WAAW,EACX,IAAI,GAAG,QAAQ,GACH;IACZ,OAAO,CACL,iBACE,SAAS,EAAE,UAAU,CACnB,qBAAqB,OAAO,aAAa,IAAI,EAAE,EAC/C;YACE,mBAAmB,EAAE,QAAQ;SAC9B,EACD,SAAS,CACV,EACD,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,IAAI,YAET,QAAQ,GACF,CACV,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/lib/ui/Button.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAGnC,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAanD,MAAM,UAAU,MAAM,CAAC,EACrB,OAAO,GAAG,SAAS,EACnB,QAAQ,EACR,IAAI,GAAG,QAAQ,EACf,QAAQ,GAAG,KAAK,EAChB,OAAO,EACP,SAAS,EACT,WAAW,EACX,IAAI,GAAG,QAAQ,EACf,OAAO,GAAG,KAAK,GACH;IACZ,OAAO,CACL,kBACE,SAAS,EAAE,UAAU,CACnB,qBAAqB,OAAO,aAAa,IAAI,EAAE,EAC/C;YACE,mBAAmB,EAAE,QAAQ;YAC7B,kBAAkB,EAAE,OAAO;SAC5B,EACD,SAAS,CACV,EACD,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;YACb,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;gBACxB,CAAC,CAAC,cAAc,EAAE,CAAA;gBAClB,OAAM;YACR,CAAC;YAED,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;QACd,CAAC,EACD,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,IAAI,aAEV,eAAM,SAAS,EAAC,kBAAkB,YAAE,QAAQ,GAAQ,EACnD,OAAO,IAAI,CACV,cAAK,SAAS,EAAC,kBAAkB,YAC/B,KAAC,OAAO,IAAC,IAAI,EAAC,OAAO,GAAG,GACpB,CACP,IACM,CACV,CAAA;AACH,CAAC"}
@@ -1,3 +1,6 @@
1
- /// <reference types="react" />
1
+ import type { Ref } from 'react';
2
2
  import type { ButtonProps } from '../../lib/ui/types.js';
3
- export declare function IconButton({ className, ...props }: ButtonProps): JSX.Element;
3
+ export type IconProps = ButtonProps & {
4
+ elRef?: Ref<HTMLButtonElement>;
5
+ };
6
+ export declare function IconButton({ className, elRef, ...props }: IconProps): JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import classNames from 'classnames';
3
- export function IconButton({ className, ...props }) {
4
- return (_jsx("button", { ...props, className: classNames('seam-icon-btn', className) }));
3
+ export function IconButton({ className, elRef, ...props }) {
4
+ return (_jsx("button", { ...props, ref: elRef, className: classNames('seam-icon-btn', props.disabled === true && 'seam-icon-btn-disabled', className) }));
5
5
  }
6
6
  //# sourceMappingURL=IconButton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"IconButton.js","sourceRoot":"","sources":["../../src/lib/ui/IconButton.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAInC,MAAM,UAAU,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAe;IAC7D,OAAO,CACL,oBAAY,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,eAAe,EAAE,SAAS,CAAC,GAAI,CACzE,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"IconButton.js","sourceRoot":"","sources":["../../src/lib/ui/IconButton.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AASnC,MAAM,UAAU,UAAU,CAAC,EACzB,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACE;IACV,OAAO,CACL,oBACM,KAAK,EACT,GAAG,EAAE,KAAK,EACV,SAAS,EAAE,UAAU,CACnB,eAAe,EACf,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,wBAAwB,EACnD,SAAS,CACV,GACD,CACH,CAAA;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type ReactNode, type Ref } from 'react';
2
+ export interface PopoverInstance {
3
+ show: () => void;
4
+ hide: () => void;
5
+ toggle: () => void;
6
+ }
7
+ type PopoverChildren = (params: {
8
+ setRef: (ref: HTMLElement | undefined | null) => void;
9
+ } & PopoverInstance) => ReactNode;
10
+ export interface PopoverProps {
11
+ children: PopoverChildren;
12
+ content: ReactNode | ((instance: PopoverInstance) => ReactNode);
13
+ instanceRef?: Ref<PopoverInstance>;
14
+ preventCloseOnClickOutside?: boolean;
15
+ }
16
+ export declare function Popover(props: PopoverProps): JSX.Element;
17
+ export {};
@@ -0,0 +1,85 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { autoUpdate, flip, limitShift, offset, shift, useFloating, } from '@floating-ui/react';
3
+ import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
4
+ import { createPortal } from 'react-dom';
5
+ import { seamComponentsClassName } from '../../../lib/seam/SeamProvider.js';
6
+ export function Popover(props) {
7
+ const { children, content, instanceRef, preventCloseOnClickOutside } = props;
8
+ const [open, setOpen] = useState(false);
9
+ const { refs, floatingStyles } = useFloating({
10
+ whileElementsMounted: autoUpdate,
11
+ transform: false,
12
+ open,
13
+ onOpenChange: setOpen,
14
+ placement: 'bottom',
15
+ middleware: [
16
+ shift({
17
+ crossAxis: true,
18
+ limiter: limitShift(),
19
+ }),
20
+ flip(),
21
+ offset(5),
22
+ ],
23
+ });
24
+ const referenceEl = useRef();
25
+ const floatingEl = useRef();
26
+ const setFLoating = useCallback((ref) => {
27
+ refs.setFloating(ref);
28
+ floatingEl.current = ref;
29
+ }, [refs, floatingEl]);
30
+ const toggle = useCallback(() => {
31
+ setOpen((value) => !value);
32
+ }, []);
33
+ const instance = useMemo(() => ({
34
+ show: () => {
35
+ setOpen(true);
36
+ },
37
+ hide: () => {
38
+ setOpen(false);
39
+ },
40
+ toggle,
41
+ }), [toggle]);
42
+ const setReference = useCallback((ref) => {
43
+ if (!(ref instanceof HTMLElement) || referenceEl.current === ref)
44
+ return;
45
+ if (referenceEl.current != null) {
46
+ referenceEl.current.removeEventListener('click', toggle);
47
+ }
48
+ refs.setReference(ref);
49
+ ref.addEventListener('click', toggle);
50
+ referenceEl.current = ref;
51
+ }, [toggle, refs]);
52
+ useImperativeHandle(instanceRef, () => instance);
53
+ /**
54
+ * Closes the popover when the user clicks outside of it.
55
+ */
56
+ const windowClickHandler = useCallback((e) => {
57
+ const target = e.target;
58
+ // If the target is the reference element, do nothing.
59
+ if (referenceEl.current === target ||
60
+ referenceEl.current?.contains(target) === true) {
61
+ return;
62
+ }
63
+ const closest = target.closest('[data-seam-popover]');
64
+ // Prevents closing if target is floating element, also adds support for nested popovers somehow :)
65
+ if (closest != null &&
66
+ referenceEl.current != null &&
67
+ !closest.contains(referenceEl.current)) {
68
+ return;
69
+ }
70
+ setOpen(false);
71
+ }, []);
72
+ useEffect(() => {
73
+ setTimeout(() => {
74
+ if (preventCloseOnClickOutside === false)
75
+ return;
76
+ globalThis.addEventListener('click', windowClickHandler);
77
+ }, 0);
78
+ return () => {
79
+ globalThis.removeEventListener('click', windowClickHandler);
80
+ };
81
+ }, [windowClickHandler, preventCloseOnClickOutside]);
82
+ return (_jsxs(_Fragment, { children: [children({ setRef: setReference, ...instance }), open &&
83
+ createPortal(_jsx("div", { className: seamComponentsClassName, "data-seam-popover": '', ref: setFLoating, style: floatingStyles, children: _jsx("div", { className: 'seam-popover', children: typeof content === 'function' ? content(instance) : content }) }), globalThis.document.body)] }));
84
+ }
85
+ //# sourceMappingURL=Popover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Popover.js","sourceRoot":"","sources":["../../../src/lib/ui/Popover/Popover.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ export interface PopoverContentPromptProps {
3
+ onConfirm?: () => void;
4
+ onCancel?: () => void;
5
+ prompt?: string;
6
+ description?: string;
7
+ confirmText?: string;
8
+ cancelText?: string;
9
+ confirmLoading?: boolean;
10
+ }
11
+ export declare function PopoverContentPrompt(props: PopoverContentPromptProps): JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '../../../lib/ui/Button.js';
3
+ export function PopoverContentPrompt(props) {
4
+ const { confirmText = t.confirm, cancelText = t.cancel, confirmLoading = false, prompt = t.areYouSure, description, onConfirm, onCancel, } = props;
5
+ return (_jsxs("div", { className: 'seam-popover-content-prompt', children: [_jsxs("div", { children: [_jsx("div", { className: 'seam-popover-content-prompt-text', children: prompt }), description != null && (_jsx("div", { className: 'seam-popover-content-prompt-description', children: description }))] }), _jsxs("div", { className: 'seam-popover-content-prompt-buttons', children: [_jsx(Button, { variant: 'solid', onClick: onConfirm, loading: confirmLoading, size: 'small', children: confirmText }), _jsx(Button, { variant: 'danger', size: 'small', onClick: onCancel, children: cancelText })] })] }));
6
+ }
7
+ const t = {
8
+ confirm: 'Confirm',
9
+ cancel: 'Cancel',
10
+ areYouSure: 'Are you sure?',
11
+ };
12
+ //# sourceMappingURL=PopoverContentPrompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PopoverContentPrompt.js","sourceRoot":"","sources":["../../../src/lib/ui/Popover/PopoverContentPrompt.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAYzC,MAAM,UAAU,oBAAoB,CAClC,KAAgC;IAEhC,MAAM,EACJ,WAAW,GAAG,CAAC,CAAC,OAAO,EACvB,UAAU,GAAG,CAAC,CAAC,MAAM,EACrB,cAAc,GAAG,KAAK,EACtB,MAAM,GAAG,CAAC,CAAC,UAAU,EACrB,WAAW,EACX,SAAS,EACT,QAAQ,GACT,GAAG,KAAK,CAAA;IAET,OAAO,CACL,eAAK,SAAS,EAAC,6BAA6B,aAC1C,0BACE,cAAK,SAAS,EAAC,kCAAkC,YAAE,MAAM,GAAO,EAC/D,WAAW,IAAI,IAAI,IAAI,CACtB,cAAK,SAAS,EAAC,yCAAyC,YACrD,WAAW,GACR,CACP,IACG,EACN,eAAK,SAAS,EAAC,qCAAqC,aAClD,KAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAC,OAAO,YAEX,WAAW,GACL,EAET,KAAC,MAAM,IAAC,OAAO,EAAC,QAAQ,EAAC,IAAI,EAAC,OAAO,EAAC,OAAO,EAAE,QAAQ,YACpD,UAAU,GACJ,IACL,IACF,CACP,CAAA;AACH,CAAC;AAED,MAAM,CAAC,GAAG;IACR,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,eAAe;CAC5B,CAAA"}
@@ -1,9 +1,14 @@
1
- /// <reference types="react" />
1
+ import type { CSSProperties } from 'react';
2
2
  import type { HvacModeSetting } from '../../../lib/seam/thermostats/thermostat-device.js';
3
3
  interface ClimateModeMenuProps {
4
4
  mode: HvacModeSetting;
5
5
  onChange: (mode: HvacModeSetting) => void;
6
6
  supportedModes?: HvacModeSetting[];
7
+ buttonTextVisible?: boolean;
8
+ className?: string;
9
+ style?: CSSProperties;
10
+ block?: boolean;
11
+ size?: 'regular' | 'large';
7
12
  }
8
- export declare function ClimateModeMenu({ mode, onChange, supportedModes, }: ClimateModeMenuProps): JSX.Element;
13
+ export declare function ClimateModeMenu({ mode, onChange, supportedModes, buttonTextVisible, className, style, block, size, }: ClimateModeMenuProps): JSX.Element;
9
14
  export {};
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import classNames from 'classnames';
2
3
  import { ChevronDownIcon } from '../../../lib/icons/ChevronDown.js';
3
4
  import { OffIcon } from '../../../lib/icons/Off.js';
4
5
  import { ThermostatCoolIcon } from '../../../lib/icons/ThermostatCool.js';
@@ -6,8 +7,12 @@ import { ThermostatHeatIcon } from '../../../lib/icons/ThermostatHeat.js';
6
7
  import { ThermostatHeatCoolIcon } from '../../../lib/icons/ThermostatHeatCool.js';
7
8
  import { Menu } from '../../../lib/ui/Menu/Menu.js';
8
9
  import { ThermoModeMenuOption } from '../../../lib/ui/thermostat/ThermoModeMenuOption.js';
9
- export function ClimateModeMenu({ mode, onChange, supportedModes = ['heat', 'cool', 'heat_cool', 'off'], }) {
10
- return (_jsx(Menu, { renderButton: ({ onOpen }) => (_jsxs("button", { onClick: onOpen, className: 'seam-climate-mode-menu-button', children: [_jsx("div", { className: 'seam-climate-mode-menu-button-icon', children: _jsx(ModeIcon, { mode: mode }) }), _jsx(ChevronDownIcon, { className: 'seam-climate-mode-menu-button-chevron' })] })), verticalOffset: -180, horizontalOffset: -32, backgroundProps: {
10
+ export function ClimateModeMenu({ mode, onChange, supportedModes = ['heat', 'cool', 'heat_cool', 'off'], buttonTextVisible = false, className, style, block, size = 'regular', }) {
11
+ return (_jsx(Menu, { renderButton: ({ onOpen }) => (_jsxs("button", { style: style, onClick: onOpen, className: classNames('seam-climate-mode-menu-button', {
12
+ 'seam-climate-mode-menu-button-block': block,
13
+ 'seam-climate-mode-menu-button-regular': size === 'regular',
14
+ 'seam-climate-mode-menu-button-large': size === 'large',
15
+ }, className), children: [_jsx("div", { className: 'seam-climate-mode-menu-button-icon', children: _jsx(ModeIcon, { mode: mode }) }), buttonTextVisible && (_jsx("span", { className: 'seam-climate-mode-menu-button-text', children: t[mode] })), _jsx(ChevronDownIcon, { className: 'seam-climate-mode-menu-button-chevron' })] })), verticalOffset: -180, horizontalOffset: -32, backgroundProps: {
11
16
  className: 'seam-thermo-mode-menu',
12
17
  }, children: supportedModes.map((m) => (_jsx(ThermoModeMenuOption, { label: t[m], icon: _jsx(ModeIcon, { mode: m }), isSelected: mode === m, onClick: () => {
13
18
  onChange(m);
@@ -1 +1 @@
1
- {"version":3,"file":"ClimateModeMenu.js","sourceRoot":"","sources":["../../../src/lib/ui/thermostat/ClimateModeMenu.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AAExE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAQhF,MAAM,UAAU,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,EACR,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,GAChC;IACrB,OAAO,CACL,KAAC,IAAI,IACH,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAC5B,kBAAQ,OAAO,EAAE,MAAM,EAAE,SAAS,EAAC,+BAA+B,aAChE,cAAK,SAAS,EAAC,oCAAoC,YACjD,KAAC,QAAQ,IAAC,IAAI,EAAE,IAAI,GAAI,GACpB,EACN,KAAC,eAAe,IAAC,SAAS,EAAC,uCAAuC,GAAG,IAC9D,CACV,EACD,cAAc,EAAE,CAAC,GAAG,EACpB,gBAAgB,EAAE,CAAC,EAAE,EACrB,eAAe,EAAE;YACf,SAAS,EAAE,uBAAuB;SACnC,YAEA,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACzB,KAAC,oBAAoB,IAEnB,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EACX,IAAI,EAAE,KAAC,QAAQ,IAAC,IAAI,EAAE,CAAC,GAAI,EAC3B,UAAU,EAAE,IAAI,KAAK,CAAC,EACtB,OAAO,EAAE,GAAG,EAAE;gBACZ,QAAQ,CAAC,CAAC,CAAC,CAAA;YACb,CAAC,IANI,CAAC,CAON,CACH,CAAC,GACG,CACR,CAAA;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAgC;IAChD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM;YACT,OAAO,KAAC,kBAAkB,KAAG,CAAA;QAC/B,KAAK,MAAM;YACT,OAAO,KAAC,kBAAkB,KAAG,CAAA;QAC/B,KAAK,WAAW;YACd,OAAO,KAAC,sBAAsB,KAAG,CAAA;QACnC,KAAK,KAAK;YACR,OAAO,KAAC,OAAO,KAAG,CAAA;IACtB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,GAAG;IACR,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,aAAa;IACxB,GAAG,EAAE,KAAK;CACX,CAAA"}
1
+ {"version":3,"file":"ClimateModeMenu.js","sourceRoot":"","sources":["../../../src/lib/ui/thermostat/ClimateModeMenu.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAGnC,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AAExE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAahF,MAAM,UAAU,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,EACR,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EACrD,iBAAiB,GAAG,KAAK,EACzB,SAAS,EACT,KAAK,EACL,KAAK,EACL,IAAI,GAAG,SAAS,GACK;IACrB,OAAO,CACL,KAAC,IAAI,IACH,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAC5B,kBACE,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,UAAU,CACnB,+BAA+B,EAC/B;gBACE,qCAAqC,EAAE,KAAK;gBAC5C,uCAAuC,EAAE,IAAI,KAAK,SAAS;gBAC3D,qCAAqC,EAAE,IAAI,KAAK,OAAO;aACxD,EACD,SAAS,CACV,aAED,cAAK,SAAS,EAAC,oCAAoC,YACjD,KAAC,QAAQ,IAAC,IAAI,EAAE,IAAI,GAAI,GACpB,EAEL,iBAAiB,IAAI,CACpB,eAAM,SAAS,EAAC,oCAAoC,YACjD,CAAC,CAAC,IAAI,CAAC,GACH,CACR,EAED,KAAC,eAAe,IAAC,SAAS,EAAC,uCAAuC,GAAG,IAC9D,CACV,EACD,cAAc,EAAE,CAAC,GAAG,EACpB,gBAAgB,EAAE,CAAC,EAAE,EACrB,eAAe,EAAE;YACf,SAAS,EAAE,uBAAuB;SACnC,YAEA,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACzB,KAAC,oBAAoB,IAEnB,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EACX,IAAI,EAAE,KAAC,QAAQ,IAAC,IAAI,EAAE,CAAC,GAAI,EAC3B,UAAU,EAAE,IAAI,KAAK,CAAC,EACtB,OAAO,EAAE,GAAG,EAAE;gBACZ,QAAQ,CAAC,CAAC,CAAC,CAAA;YACb,CAAC,IANI,CAAC,CAON,CACH,CAAC,GACG,CACR,CAAA;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAgC;IAChD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM;YACT,OAAO,KAAC,kBAAkB,KAAG,CAAA;QAC/B,KAAK,MAAM;YACT,OAAO,KAAC,kBAAkB,KAAG,CAAA;QAC/B,KAAK,WAAW;YACd,OAAO,KAAC,sBAAsB,KAAG,CAAA;QACnC,KAAK,KAAK;YACR,OAAO,KAAC,OAAO,KAAG,CAAA;IACtB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,GAAG;IACR,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,aAAa;IACxB,GAAG,EAAE,KAAK;CACX,CAAA"}
@@ -0,0 +1,8 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ import type { ThermostatClimatePreset, ThermostatDevice } from '../../../lib/seam/thermostats/thermostat-device.js';
3
+ export type ClimatePresetProps = {
4
+ preset?: ThermostatClimatePreset;
5
+ onBack: () => void;
6
+ device: ThermostatDevice;
7
+ } & Omit<HTMLAttributes<HTMLDivElement>, 'children'>;
8
+ export declare function ClimatePreset(props: ClimatePresetProps): JSX.Element;
@@ -0,0 +1,141 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import classNames from 'classnames';
3
+ import { useCallback, useImperativeHandle, useMemo, } from 'react';
4
+ import { Controller, useForm } from 'react-hook-form';
5
+ import { fahrenheitToCelsius } from '../../../lib/seam/thermostats/unit-conversion.js';
6
+ import { useCreateThermostatClimatePreset } from '../../../lib/seam/thermostats/use-create-thermostat-climate-preset.js';
7
+ import { useUpdateThermostatClimatePreset } from '../../../lib/seam/thermostats/use-update-thermostat-climate-preset.js';
8
+ import { Button } from '../../../lib/ui/Button.js';
9
+ import { FormField } from '../../../lib/ui/FormField.js';
10
+ import { InputLabel } from '../../../lib/ui/InputLabel.js';
11
+ import { ContentHeader } from '../../../lib/ui/layout/ContentHeader.js';
12
+ import { TextField } from '../../../lib/ui/TextField/TextField.js';
13
+ import { ClimateModeMenu } from '../../../lib/ui/thermostat/ClimateModeMenu.js';
14
+ import { FanModeMenu } from '../../../lib/ui/thermostat/FanModeMenu.js';
15
+ import { TemperatureControlGroup } from '../../../lib/ui/thermostat/TemperatureControlGroup.js';
16
+ export function ClimatePreset(props) {
17
+ const { preset, onBack, device, ...attrs } = props;
18
+ return (_jsxs("div", { ...attrs, className: classNames('seam-thermostat-climate-preset', attrs.className), children: [_jsx(ContentHeader, { title: preset == null ? t.crateNewPreset : preset.display_name, onBack: onBack }), preset == null ? (_jsx(CreateForm, { device: device, onComplete: onBack })) : (_jsx(UpdateForm, { device: device, onComplete: onBack, preset: preset }))] }));
19
+ }
20
+ function PresetForm(props) {
21
+ const { defaultValues, device, instanceRef, loading, onSubmit, withKeyField, } = props;
22
+ const form = useForm({ defaultValues });
23
+ useImperativeHandle(instanceRef, () => form);
24
+ const { register, handleSubmit, formState: { errors }, watch, setValue, control, } = form;
25
+ const state = watch();
26
+ const onHvacModeChange = (mode) => {
27
+ if (mode === 'heat_cool') {
28
+ setValue('heatPoint', defaultValues.heatPoint);
29
+ setValue('coolPoint', defaultValues.coolPoint);
30
+ }
31
+ else if (mode === 'heat') {
32
+ setValue('heatPoint', defaultValues.heatPoint);
33
+ setValue('coolPoint', undefined);
34
+ }
35
+ else if (mode === 'cool') {
36
+ setValue('heatPoint', undefined);
37
+ setValue('coolPoint', defaultValues.coolPoint);
38
+ }
39
+ else {
40
+ setValue('heatPoint', undefined);
41
+ setValue('coolPoint', undefined);
42
+ }
43
+ };
44
+ const otherClimatePresets = useMemo(() => {
45
+ if (withKeyField !== true)
46
+ return [];
47
+ return (device.properties.available_climate_presets ?? []).filter((other) => other.climate_preset_key !== defaultValues.key);
48
+ }, [defaultValues, device, withKeyField]);
49
+ const onValid = useCallback(() => {
50
+ onSubmit(state);
51
+ }, [onSubmit, state]);
52
+ return (_jsx("div", { className: 'seam-main', children: _jsxs("form", { onSubmit: (e) => {
53
+ void handleSubmit(onValid)(e);
54
+ }, children: [withKeyField === true && (_jsxs(FormField, { children: [_jsx(InputLabel, { children: "Key" }), _jsx(TextField, { size: 'large', clearable: true, hasError: errors.key != null, helperText: errors.key?.message, inputProps: {
55
+ ...register('key', {
56
+ required: 'required',
57
+ setValueAs: (value) => value.trim(),
58
+ validate(value) {
59
+ if (value.includes(' ')) {
60
+ return t.keyCannotContainSpaces;
61
+ }
62
+ const exists = otherClimatePresets.some((other) => other.climate_preset_key === value);
63
+ if (exists) {
64
+ return t.keyAlreadyExists;
65
+ }
66
+ return true;
67
+ },
68
+ }),
69
+ } })] })), _jsxs(FormField, { children: [_jsx(InputLabel, { children: t.nameField }), _jsx(TextField, { size: 'large', clearable: true, hasError: errors.name != null, helperText: errors.name?.message, inputProps: register('name', {
70
+ required: false,
71
+ setValueAs: (value) => value.trim(),
72
+ }) })] }), state.fanMode != null && (_jsxs(FormField, { children: [_jsx(InputLabel, { children: t.fanModeField }), _jsx(Controller, { control: control, name: 'fanMode', render: ({ field: { onChange, value } }) => value != null ? (_jsx(FanModeMenu, { block: true, size: 'large', mode: value, onChange: onChange })) : (_jsx(_Fragment, {})) })] })), state.hvacMode != null && (_jsxs(FormField, { children: [_jsx(InputLabel, { children: t.hvacModeField }), _jsx(Controller, { control: control, name: 'hvacMode', render: ({ field: { onChange, value } }) => value == null ? (_jsx(_Fragment, {})) : (_jsx(ClimateModeMenu, { block: true, size: 'large', buttonTextVisible: true, mode: value, onChange: (value) => {
73
+ onHvacModeChange(value);
74
+ onChange(value);
75
+ } })) })] })), state.hvacMode !== 'off' && state.hvacMode != null && (_jsxs(FormField, { children: [_jsx(InputLabel, { children: t.heatCoolField }), _jsx(TemperatureControlGroup, { mode: state.hvacMode, onHeatValueChange: (value) => {
76
+ setValue('heatPoint', value);
77
+ }, onCoolValueChange: (value) => {
78
+ setValue('coolPoint', value);
79
+ }, heatValue: state.heatPoint ?? 0, coolValue: state.coolPoint ?? 0, minHeat: device.properties.min_heating_cooling_delta_fahrenheit, maxHeat: device.properties.max_heating_set_point_fahrenheit, minCool: device.properties.min_cooling_set_point_fahrenheit, maxCool: device.properties.max_cooling_set_point_fahrenheit, delta: device.properties.min_heating_cooling_delta_fahrenheit })] })), _jsx("div", { className: 'seam-climate-preset-buttons', children: _jsx(Button, { type: 'submit', variant: 'solid', disabled: loading, loading: loading, children: t.save }) })] }) }));
80
+ }
81
+ function CreateForm({ device, onComplete }) {
82
+ const mutation = useCreateThermostatClimatePreset();
83
+ const onSubmit = useCallback((values) => {
84
+ mutation.mutate({
85
+ climate_preset_key: values.key,
86
+ device_id: device.device_id,
87
+ name: values.name === '' ? undefined : values.name,
88
+ cooling_set_point_fahrenheit: values.coolPoint,
89
+ heating_set_point_fahrenheit: values.heatPoint,
90
+ fan_mode_setting: values.fanMode,
91
+ cooling_set_point_celsius: fahrenheitToCelsius(values.coolPoint),
92
+ heating_set_point_celsius: fahrenheitToCelsius(values.heatPoint),
93
+ hvac_mode_setting: values.hvacMode,
94
+ }, { onSuccess: onComplete });
95
+ }, [device, mutation, onComplete]);
96
+ return (_jsx(PresetForm, { defaultValues: {
97
+ key: '',
98
+ coolPoint: 60,
99
+ heatPoint: 80,
100
+ name: '',
101
+ hvacMode: 'off',
102
+ fanMode: 'auto',
103
+ }, device: device, loading: mutation.isPending, onSubmit: onSubmit, withKeyField: true }));
104
+ }
105
+ function UpdateForm({ device, onComplete, preset, }) {
106
+ const mutation = useUpdateThermostatClimatePreset();
107
+ const defaultValues = useMemo(() => ({
108
+ coolPoint: preset.cooling_set_point_fahrenheit ?? 60,
109
+ heatPoint: preset.heating_set_point_fahrenheit ?? 80,
110
+ name: preset.display_name,
111
+ hvacMode: preset.hvac_mode_setting,
112
+ fanMode: preset.fan_mode_setting,
113
+ key: preset.climate_preset_key,
114
+ }), [preset]);
115
+ const onSubmit = useCallback((values) => {
116
+ mutation.mutate({
117
+ climate_preset_key: values.key,
118
+ device_id: device.device_id,
119
+ name: values.name === '' ? undefined : values.name,
120
+ cooling_set_point_fahrenheit: values.coolPoint,
121
+ heating_set_point_fahrenheit: values.heatPoint,
122
+ fan_mode_setting: values.fanMode,
123
+ cooling_set_point_celsius: fahrenheitToCelsius(values.coolPoint),
124
+ heating_set_point_celsius: fahrenheitToCelsius(values.heatPoint),
125
+ hvac_mode_setting: values.hvacMode,
126
+ }, { onSuccess: onComplete });
127
+ }, [device, mutation, onComplete]);
128
+ return (_jsx(PresetForm, { defaultValues: defaultValues, device: device, loading: mutation.isPending, onSubmit: onSubmit }));
129
+ }
130
+ const t = {
131
+ keyAlreadyExists: 'Climate Preset with this key already exists.',
132
+ keyCannotContainSpaces: 'Climate Preset key cannot contain spaces.',
133
+ nameField: 'Display Name (Optional)',
134
+ fanModeField: 'Fan Mode',
135
+ hvacModeField: 'HVAC Mode',
136
+ heatCoolField: 'Heat / Cool',
137
+ delete: 'Delete',
138
+ save: 'Save',
139
+ crateNewPreset: 'Create New Climate Preset',
140
+ };
141
+ //# sourceMappingURL=ClimatePreset.js.map