@seamapi/react 4.5.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 (83) hide show
  1. package/README.md +2 -2
  2. package/dist/elements.js +11560 -9368
  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/AccessCodeDetails/AccessCodeDetails.js +8 -3
  12. package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js.map +1 -1
  13. package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js +17 -1
  14. package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js.map +1 -1
  15. package/lib/seam/thermostats/thermostat-device.d.ts +2 -1
  16. package/lib/seam/thermostats/thermostat-device.js.map +1 -1
  17. package/lib/seam/thermostats/unit-conversion.d.ts +5 -2
  18. package/lib/seam/thermostats/unit-conversion.js +5 -2
  19. package/lib/seam/thermostats/unit-conversion.js.map +1 -1
  20. package/lib/seam/thermostats/use-create-thermostat-climate-preset.d.ts +6 -0
  21. package/lib/seam/thermostats/use-create-thermostat-climate-preset.js +55 -0
  22. package/lib/seam/thermostats/use-create-thermostat-climate-preset.js.map +1 -0
  23. package/lib/seam/thermostats/use-delete-thermostat-climate-preset.d.ts +6 -0
  24. package/lib/seam/thermostats/use-delete-thermostat-climate-preset.js +44 -0
  25. package/lib/seam/thermostats/use-delete-thermostat-climate-preset.js.map +1 -0
  26. package/lib/seam/thermostats/use-update-thermostat-climate-preset.d.ts +6 -0
  27. package/lib/seam/thermostats/use-update-thermostat-climate-preset.js +55 -0
  28. package/lib/seam/thermostats/use-update-thermostat-climate-preset.js.map +1 -0
  29. package/lib/ui/Button.d.ts +3 -2
  30. package/lib/ui/Button.js +12 -4
  31. package/lib/ui/Button.js.map +1 -1
  32. package/lib/ui/IconButton.d.ts +5 -2
  33. package/lib/ui/IconButton.js +2 -2
  34. package/lib/ui/IconButton.js.map +1 -1
  35. package/lib/ui/Popover/Popover.d.ts +17 -0
  36. package/lib/ui/Popover/Popover.js +85 -0
  37. package/lib/ui/Popover/Popover.js.map +1 -0
  38. package/lib/ui/Popover/PopoverContentPrompt.d.ts +11 -0
  39. package/lib/ui/Popover/PopoverContentPrompt.js +12 -0
  40. package/lib/ui/Popover/PopoverContentPrompt.js.map +1 -0
  41. package/lib/ui/thermostat/ClimateModeMenu.d.ts +7 -2
  42. package/lib/ui/thermostat/ClimateModeMenu.js +7 -2
  43. package/lib/ui/thermostat/ClimateModeMenu.js.map +1 -1
  44. package/lib/ui/thermostat/ClimatePreset.d.ts +8 -0
  45. package/lib/ui/thermostat/ClimatePreset.js +141 -0
  46. package/lib/ui/thermostat/ClimatePreset.js.map +1 -0
  47. package/lib/ui/thermostat/ClimatePresets.d.ts +9 -0
  48. package/lib/ui/thermostat/ClimatePresets.js +72 -0
  49. package/lib/ui/thermostat/ClimatePresets.js.map +1 -0
  50. package/lib/ui/thermostat/FanModeMenu.d.ts +3 -1
  51. package/lib/ui/thermostat/FanModeMenu.js +5 -2
  52. package/lib/ui/thermostat/FanModeMenu.js.map +1 -1
  53. package/lib/ui/thermostat/ThermostatCard.d.ts +1 -0
  54. package/lib/ui/thermostat/ThermostatCard.js +4 -2
  55. package/lib/ui/thermostat/ThermostatCard.js.map +1 -1
  56. package/lib/ui/types.d.ts +3 -3
  57. package/lib/version.d.ts +1 -1
  58. package/lib/version.js +1 -1
  59. package/package.json +3 -2
  60. package/src/lib/icons/Trash.tsx +28 -0
  61. package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx +50 -34
  62. package/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx +52 -1
  63. package/src/lib/seam/thermostats/thermostat-device.ts +4 -0
  64. package/src/lib/seam/thermostats/unit-conversion.ts +12 -2
  65. package/src/lib/seam/thermostats/use-create-thermostat-climate-preset.ts +101 -0
  66. package/src/lib/seam/thermostats/use-delete-thermostat-climate-preset.ts +84 -0
  67. package/src/lib/seam/thermostats/use-update-thermostat-climate-preset.ts +103 -0
  68. package/src/lib/ui/Button.tsx +20 -3
  69. package/src/lib/ui/IconButton.tsx +19 -2
  70. package/src/lib/ui/Popover/Popover.tsx +168 -0
  71. package/src/lib/ui/Popover/PopoverContentPrompt.tsx +58 -0
  72. package/src/lib/ui/thermostat/ClimateModeMenu.tsx +33 -1
  73. package/src/lib/ui/thermostat/ClimatePreset.tsx +373 -0
  74. package/src/lib/ui/thermostat/ClimatePresets.tsx +235 -0
  75. package/src/lib/ui/thermostat/FanModeMenu.tsx +20 -2
  76. package/src/lib/ui/thermostat/ThermostatCard.tsx +10 -4
  77. package/src/lib/ui/types.ts +3 -3
  78. package/src/lib/version.ts +1 -1
  79. package/src/styles/_buttons.scss +56 -2
  80. package/src/styles/_main.scss +2 -0
  81. package/src/styles/_popover.scss +46 -0
  82. package/src/styles/_spinner.scss +1 -1
  83. package/src/styles/_thermostat.scss +154 -2
@@ -0,0 +1,235 @@
1
+ import classNames from 'classnames'
2
+ import { type HTMLAttributes, type ReactNode, useState } from 'react'
3
+
4
+ import { AddIcon } from 'lib/icons/Add.js'
5
+ import { EditIcon } from 'lib/icons/Edit.js'
6
+ import { FanIcon } from 'lib/icons/Fan.js'
7
+ import { ThermostatCoolIcon } from 'lib/icons/ThermostatCool.js'
8
+ import { ThermostatHeatIcon } from 'lib/icons/ThermostatHeat.js'
9
+ import { TrashIcon } from 'lib/icons/Trash.js'
10
+ import type {
11
+ ThermostatClimatePreset,
12
+ ThermostatDevice,
13
+ } from 'lib/seam/thermostats/thermostat-device.js'
14
+ import { getTemperatureUnitSymbol } from 'lib/seam/thermostats/unit-conversion.js'
15
+ import { useDeleteThermostatClimatePreset } from 'lib/seam/thermostats/use-delete-thermostat-climate-preset.js'
16
+ import { Button } from 'lib/ui/Button.js'
17
+ import { IconButton } from 'lib/ui/IconButton.js'
18
+ import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
19
+ import { Popover } from 'lib/ui/Popover/Popover.js'
20
+ import { PopoverContentPrompt } from 'lib/ui/Popover/PopoverContentPrompt.js'
21
+ import { Spinner } from 'lib/ui/Spinner/Spinner.js'
22
+ import { ClimatePreset } from 'lib/ui/thermostat/ClimatePreset.js'
23
+
24
+ interface ClimatePresetsManagement {
25
+ device: ThermostatDevice
26
+ onBack: () => void
27
+ temperatureUnit: 'fahrenheit' | 'celsius'
28
+ }
29
+
30
+ const CreateNewPresetSymbol = Symbol('CreateNewPreset')
31
+
32
+ export function ClimatePresets(props: ClimatePresetsManagement): JSX.Element {
33
+ const { device, onBack } = props
34
+
35
+ const [selectedClimatePreset, setSelectedClimatePreset] = useState<
36
+ ThermostatClimatePreset | typeof CreateNewPresetSymbol | null
37
+ >(null)
38
+
39
+ const [
40
+ climatePresetKeySelectedForDeletion,
41
+ setClimatePresetKeySelectedForDeletion,
42
+ ] = useState<ThermostatClimatePreset['climate_preset_key'] | null>(null)
43
+ const deleteMutation = useDeleteThermostatClimatePreset()
44
+
45
+ if (
46
+ selectedClimatePreset != null ||
47
+ selectedClimatePreset === CreateNewPresetSymbol
48
+ ) {
49
+ return (
50
+ <ClimatePreset
51
+ onBack={() => {
52
+ setSelectedClimatePreset(null)
53
+ }}
54
+ device={device}
55
+ preset={
56
+ selectedClimatePreset === CreateNewPresetSymbol
57
+ ? undefined
58
+ : selectedClimatePreset
59
+ }
60
+ />
61
+ )
62
+ }
63
+
64
+ return (
65
+ <div className='seam-thermostat-climate-presets'>
66
+ <ContentHeader title={t.title} onBack={onBack} />
67
+ <div className='seam-thermostat-climate-presets-body'>
68
+ <Button
69
+ onClick={() => {
70
+ setSelectedClimatePreset(CreateNewPresetSymbol)
71
+ }}
72
+ className='seam-climate-presets-add-button'
73
+ >
74
+ <AddIcon />
75
+ {t.createNew}
76
+ </Button>
77
+
78
+ <div className='seam-thermostat-climate-presets-cards'>
79
+ {device.properties.available_climate_presets.map((preset) => (
80
+ <PresetCard
81
+ onClickEdit={() => {
82
+ setSelectedClimatePreset(preset)
83
+ }}
84
+ onClickDelete={() => {
85
+ setClimatePresetKeySelectedForDeletion(
86
+ preset.climate_preset_key
87
+ )
88
+ deleteMutation.mutate({
89
+ climate_preset_key: preset.climate_preset_key,
90
+ device_id: device.device_id,
91
+ })
92
+ }}
93
+ temperatureUnit={props.temperatureUnit}
94
+ preset={preset}
95
+ key={preset.climate_preset_key}
96
+ deletionLoading={
97
+ deleteMutation.isPending &&
98
+ climatePresetKeySelectedForDeletion ===
99
+ preset.climate_preset_key
100
+ }
101
+ disabled={
102
+ deleteMutation.isPending &&
103
+ climatePresetKeySelectedForDeletion !==
104
+ preset.climate_preset_key
105
+ }
106
+ />
107
+ ))}
108
+ </div>
109
+ </div>
110
+ </div>
111
+ )
112
+ }
113
+
114
+ function PresetCard(
115
+ props: HTMLAttributes<HTMLDivElement> & {
116
+ preset: ThermostatClimatePreset
117
+ temperatureUnit: 'fahrenheit' | 'celsius'
118
+ onClickEdit: () => void
119
+ onClickDelete: () => void
120
+ deletionLoading?: boolean
121
+ disabled?: boolean
122
+ }
123
+ ): JSX.Element {
124
+ const {
125
+ preset,
126
+ temperatureUnit,
127
+ onClickEdit,
128
+ onClickDelete,
129
+ deletionLoading = false,
130
+ disabled = false,
131
+ ...attrs
132
+ } = props
133
+
134
+ const heatPoint =
135
+ temperatureUnit === 'fahrenheit'
136
+ ? preset.heating_set_point_fahrenheit
137
+ : (preset.heating_set_point_celsius ?? undefined)
138
+
139
+ const coolPoint =
140
+ temperatureUnit === 'fahrenheit'
141
+ ? preset.cooling_set_point_fahrenheit
142
+ : (preset.cooling_set_point_celsius ?? undefined)
143
+
144
+ const unitSymbol = getTemperatureUnitSymbol(temperatureUnit)
145
+
146
+ return (
147
+ <div
148
+ {...attrs}
149
+ className={classNames(
150
+ 'seam-thermostat-climate-presets-card',
151
+ attrs.className
152
+ )}
153
+ >
154
+ <div className='seam-thermostat-climate-presets-card-top'>
155
+ <div className='seam-thermostat-climate-presets-card-name'>
156
+ {preset.display_name}
157
+
158
+ {preset.name != null && (
159
+ <div className='seam-thermostat-climate-presets-card-name-key'>
160
+ {preset.climate_preset_key}
161
+ </div>
162
+ )}
163
+ </div>
164
+
165
+ <div className='seam-thermostat-climate-presets-card-buttons'>
166
+ <IconButton
167
+ disabled={disabled || deletionLoading || !preset.can_edit}
168
+ onClick={onClickEdit}
169
+ title={t.edit}
170
+ >
171
+ <EditIcon />
172
+ </IconButton>
173
+
174
+ <Popover
175
+ content={({ hide }) => (
176
+ <PopoverContentPrompt
177
+ onCancel={hide}
178
+ onConfirm={() => {
179
+ onClickDelete()
180
+ hide()
181
+ }}
182
+ />
183
+ )}
184
+ >
185
+ {({ setRef }) => (
186
+ <IconButton
187
+ elRef={setRef}
188
+ disabled={disabled || !preset.can_delete}
189
+ title={t.delete}
190
+ >
191
+ {deletionLoading ? <Spinner size='small' /> : <TrashIcon />}
192
+ </IconButton>
193
+ )}
194
+ </Popover>
195
+ </div>
196
+ </div>
197
+
198
+ <div className='seam-thermostat-climate-presets-card-body'>
199
+ {heatPoint != null && (
200
+ <Chip
201
+ icon={<ThermostatHeatIcon />}
202
+ text={`${heatPoint} ${unitSymbol}`}
203
+ />
204
+ )}
205
+
206
+ {coolPoint != null && (
207
+ <Chip
208
+ icon={<ThermostatCoolIcon />}
209
+ text={`${coolPoint} ${unitSymbol}`}
210
+ />
211
+ )}
212
+
213
+ {preset.fan_mode_setting != null && (
214
+ <Chip icon={<FanIcon />} text={preset.fan_mode_setting} />
215
+ )}
216
+ </div>
217
+ </div>
218
+ )
219
+ }
220
+
221
+ function Chip({ icon, text }: { icon: ReactNode; text: string }): JSX.Element {
222
+ return (
223
+ <div className='seam-thermostat-climate-preset-chip'>
224
+ <span className='seam-thermostat-climate-preset-chip-icon'>{icon}</span>
225
+ <span className='seam-thermostat-climate-preset-chip-value'>{text}</span>
226
+ </div>
227
+ )
228
+ }
229
+
230
+ const t = {
231
+ title: 'Climate Presets',
232
+ createNew: 'Create New',
233
+ delete: 'Delete',
234
+ edit: 'Edit',
235
+ }
@@ -1,3 +1,5 @@
1
+ import classNames from 'classnames'
2
+
1
3
  import { ChevronDownIcon } from 'lib/icons/ChevronDown.js'
2
4
  import { FanIcon } from 'lib/icons/Fan.js'
3
5
  import { FanOutlineIcon } from 'lib/icons/FanOutline.js'
@@ -10,13 +12,29 @@ const modes: FanModeSetting[] = ['auto', 'on']
10
12
  interface FanModeMenuProps {
11
13
  mode: FanModeSetting
12
14
  onChange: (mode: FanModeSetting) => void
15
+ block?: boolean
16
+ size?: 'regular' | 'large'
13
17
  }
14
18
 
15
- export function FanModeMenu({ mode, onChange }: FanModeMenuProps): JSX.Element {
19
+ export function FanModeMenu({
20
+ mode,
21
+ onChange,
22
+ block,
23
+ size = 'regular',
24
+ }: FanModeMenuProps): JSX.Element {
16
25
  return (
17
26
  <Menu
18
27
  renderButton={({ onOpen }) => (
19
- <button onClick={onOpen} className='seam-fan-mode-menu-button'>
28
+ <button
29
+ onClick={onOpen}
30
+ className={classNames(
31
+ 'seam-fan-mode-menu-button',
32
+ `seam-fan-mode-menu-button-size-${size}`,
33
+ {
34
+ 'seam-fan-mode-menu-button-block-sized': block,
35
+ }
36
+ )}
37
+ >
20
38
  <div className='seam-fan-mode-menu-button-block'>
21
39
  <FanOutlineIcon />
22
40
  <span className='seam-fan-mode-menu-button-text'>
@@ -12,12 +12,17 @@ import { Temperature } from 'lib/ui/thermostat/Temperature.js'
12
12
  interface ThermostatCardProps {
13
13
  device: ThermostatDevice
14
14
  onEditName?: (newName: string) => void
15
+ onTemperatureUnitChange?: (temperatureUnit: 'fahrenheit' | 'celsius') => void
15
16
  }
16
17
 
17
18
  export function ThermostatCard(props: ThermostatCardProps): JSX.Element {
18
19
  return (
19
20
  <div className='seam-thermostat-card'>
20
- <Content device={props.device} onEditName={props.onEditName} />
21
+ <Content
22
+ device={props.device}
23
+ onEditName={props.onEditName}
24
+ onTemperatureUnitChange={props.onTemperatureUnitChange}
25
+ />
21
26
  </div>
22
27
  )
23
28
  }
@@ -30,9 +35,10 @@ function Content(props: ThermostatCardProps): JSX.Element | null {
30
35
  >('fahrenheit')
31
36
 
32
37
  const toggleTemperatureUnit = (): void => {
33
- setTemperatureUnit(
34
- temperatureUnit === 'fahrenheit' ? 'celsius' : 'fahrenheit'
35
- )
38
+ const newUnit = temperatureUnit === 'fahrenheit' ? 'celsius' : 'fahrenheit'
39
+
40
+ setTemperatureUnit(newUnit)
41
+ props.onTemperatureUnitChange?.(newUnit)
36
42
  }
37
43
 
38
44
  const {
@@ -1,5 +1,5 @@
1
- import type { HTMLAttributes, HtmlHTMLAttributes } from 'react'
1
+ import type { ButtonHTMLAttributes, HTMLAttributes } from 'react'
2
2
 
3
3
  export type DivProps = HTMLAttributes<HTMLDivElement>
4
- export type ButtonProps = HtmlHTMLAttributes<HTMLButtonElement>
5
- export type SpanProps = HtmlHTMLAttributes<HTMLSpanElement>
4
+ export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement>
5
+ export type SpanProps = HTMLAttributes<HTMLSpanElement>
@@ -1,3 +1,3 @@
1
- const seamapiReactVersion = '4.5.0'
1
+ const seamapiReactVersion = '4.7.0'
2
2
 
3
3
  export default seamapiReactVersion
@@ -1,10 +1,11 @@
1
1
  @use './typography';
2
2
  @use './colors';
3
+ @use 'sass:color';
3
4
 
4
5
  @mixin icon-button {
5
6
  .seam-icon-btn {
6
7
  border-radius: 6px;
7
- border: 1px solid rgb(0 122 252 / 50%);
8
+ border: 1px solid rgba(colors.$primary, 50%);
8
9
  cursor: pointer;
9
10
  background: colors.$white;
10
11
  padding: 2px;
@@ -19,7 +20,19 @@
19
20
  }
20
21
 
21
22
  &:hover {
22
- background: rgb(0 122 252 / 8%);
23
+ background: rgba(colors.$primary, 0.08);
24
+ }
25
+
26
+ &.seam-icon-btn-disabled,
27
+ &:disabled {
28
+ color: colors.$text-gray-2-5;
29
+ border-color: colors.$text-gray-3;
30
+ background: colors.$white;
31
+ cursor: not-allowed;
32
+
33
+ path {
34
+ fill: colors.$text-gray-2-5;
35
+ }
23
36
  }
24
37
  }
25
38
  }
@@ -101,6 +114,23 @@
101
114
  }
102
115
  }
103
116
 
117
+ &.seam-btn-danger {
118
+ color: colors.$status-red;
119
+ border: 1px solid colors.$status-red;
120
+ background: transparent;
121
+
122
+ &:hover {
123
+ color: color.scale(colors.$status-red, $lightness: 30%);
124
+ border-color: color.scale(colors.$status-red, $lightness: 30%);
125
+ }
126
+
127
+ &.seam-btn-disabled,
128
+ &:disabled {
129
+ color: colors.$text-gray-2-5;
130
+ border-color: colors.$text-gray-2-5;
131
+ }
132
+ }
133
+
104
134
  &.seam-btn-neutral {
105
135
  color: colors.$text-gray-1;
106
136
  border: 1px solid colors.$text-gray-2-5;
@@ -125,6 +155,7 @@
125
155
  @include button-size;
126
156
  @include button-variant;
127
157
 
158
+ position: relative;
128
159
  font-weight: 600;
129
160
  cursor: pointer;
130
161
 
@@ -132,6 +163,29 @@
132
163
  &:disabled {
133
164
  cursor: not-allowed;
134
165
  }
166
+
167
+ .seam-btn-loading {
168
+ position: absolute;
169
+ top: 0;
170
+ left: 0;
171
+ width: 100%;
172
+ height: 100%;
173
+ display: flex;
174
+ justify-content: center;
175
+ align-items: center;
176
+
177
+ --spinner-color: currentcolor;
178
+ }
179
+
180
+ .seam-btn-content {
181
+ display: contents;
182
+ }
183
+
184
+ &.seam-btn-loading {
185
+ .seam-btn-content {
186
+ visibility: hidden;
187
+ }
188
+ }
135
189
  }
136
190
  }
137
191
 
@@ -30,6 +30,7 @@
30
30
  @use './tab-set';
31
31
  @use './noise-sensor';
32
32
  @use './seam-editable-device-name';
33
+ @use './popover';
33
34
 
34
35
  .seam-components {
35
36
  // Reset
@@ -68,4 +69,5 @@
68
69
  @include thermostat.all;
69
70
  @include seam-table.all;
70
71
  @include noise-sensor.all;
72
+ @include popover.all;
71
73
  }
@@ -0,0 +1,46 @@
1
+ @use './colors';
2
+
3
+ @mixin popover {
4
+ .seam-popover {
5
+ display: inline-block;
6
+ border-radius: 8px;
7
+ overflow: hidden;
8
+ box-shadow: 0 2px 10px -2px rgb(0 0 0 / 20%);
9
+ background-color: colors.$bg-a;
10
+ border: 1px solid colors.$bg-c;
11
+ }
12
+ }
13
+
14
+ @mixin popover-content-prompt {
15
+ .seam-popover-content-prompt {
16
+ display: inline-flex;
17
+ flex-flow: column nowrap;
18
+ padding: 12px;
19
+ gap: 12px;
20
+ background-color: colors.$bg-a;
21
+ }
22
+
23
+ .seam-popover-content-prompt-text {
24
+ font-weight: 600;
25
+ text-align: center;
26
+ }
27
+
28
+ .seam-popover-content-prompt-description {
29
+ font-weight: 400;
30
+ text-align: center;
31
+ color: colors.$text-gray-2;
32
+ font-size: 12px;
33
+ }
34
+
35
+ .seam-popover-content-prompt-buttons {
36
+ display: flex;
37
+ flex-flow: row nowrap;
38
+ gap: 6px;
39
+ justify-content: flex-end;
40
+ }
41
+ }
42
+
43
+ @mixin all {
44
+ @include popover;
45
+ @include popover-content-prompt;
46
+ }
@@ -17,7 +17,7 @@
17
17
  .seam-spinner {
18
18
  width: $default-size;
19
19
  height: $default-size;
20
- border: $default-border-width solid colors.$primary;
20
+ border: $default-border-width solid var(--spinner-color, colors.$primary);
21
21
  border-top: $default-border-width solid transparent;
22
22
  display: inline-block;
23
23
  border-radius: 50%;
@@ -1,4 +1,6 @@
1
1
  @use './colors';
2
+ @use 'sass:color';
3
+ @use './access-code-form' as acf;
2
4
 
3
5
  @mixin climate-setting-control-group {
4
6
  .seam-climate-setting-control-group {
@@ -542,7 +544,6 @@
542
544
  @mixin fan-mode-menu {
543
545
  .seam-fan-mode-menu-button {
544
546
  width: 130px;
545
- height: 32px;
546
547
  display: flex;
547
548
  justify-content: space-between;
548
549
  align-items: center;
@@ -554,6 +555,14 @@
554
555
  cursor: pointer;
555
556
  transition: 0.2s ease;
556
557
 
558
+ &.seam-fan-mode-menu-button-size-regular {
559
+ height: 32px;
560
+ }
561
+
562
+ &.seam-fan-mode-menu-button-size-large {
563
+ height: 48px;
564
+ }
565
+
557
566
  svg {
558
567
  font-size: 20px;
559
568
  }
@@ -579,6 +588,10 @@
579
588
  }
580
589
  }
581
590
 
591
+ &.seam-fan-mode-menu-button-block-sized {
592
+ width: 100%;
593
+ }
594
+
582
595
  .seam-fan-mode-menu-button-text {
583
596
  color: colors.$text-gray-1;
584
597
  font-size: 16px;
@@ -597,12 +610,23 @@
597
610
  border: 1px solid colors.$text-gray-3;
598
611
  background: colors.$white;
599
612
  display: flex;
600
- justify-content: space-between;
601
613
  align-items: center;
602
614
  flex-direction: row;
603
615
  cursor: pointer;
604
616
  transition: 0.2s ease;
605
617
 
618
+ &.seam-climate-mode-menu-button-regular {
619
+ height: 32px;
620
+ }
621
+
622
+ &.seam-climate-mode-menu-button-large {
623
+ height: 48px;
624
+ }
625
+
626
+ &.seam-climate-mode-menu-button-block {
627
+ width: 100%;
628
+ }
629
+
606
630
  &:hover {
607
631
  border-color: colors.$text-gray-2;
608
632
  }
@@ -618,6 +642,12 @@
618
642
 
619
643
  .seam-climate-mode-menu-button-chevron {
620
644
  font-size: 20px;
645
+ margin-left: auto;
646
+ }
647
+
648
+ .seam-climate-mode-menu-button-text {
649
+ font-size: 14px;
650
+ margin-left: 6px;
621
651
  }
622
652
  }
623
653
 
@@ -656,6 +686,126 @@
656
686
  }
657
687
  }
658
688
 
689
+ @mixin climate-presets {
690
+ .seam-thermostat-climate-presets-body {
691
+ margin: 0 24px 24px;
692
+ display: flex;
693
+ flex-flow: column nowrap;
694
+ gap: 10px;
695
+ justify-content: center;
696
+ }
697
+
698
+ .seam-thermostat-climate-presets-cards {
699
+ display: flex;
700
+ flex-flow: row wrap;
701
+ gap: 10px;
702
+ justify-content: center;
703
+ }
704
+
705
+ .seam-climate-presets-add-button {
706
+ margin: 0 auto;
707
+ display: inline-flex !important;
708
+ align-items: center;
709
+ gap: 6px;
710
+
711
+ svg {
712
+ font-size: 20px;
713
+ }
714
+
715
+ svg,
716
+ path {
717
+ fill: currentcolor;
718
+ }
719
+ }
720
+
721
+ .seam-thermostat-climate-presets-card {
722
+ border-radius: 12px;
723
+ background-color: colors.$bg-a;
724
+ width: 100%;
725
+ max-width: 250px;
726
+ overflow: hidden;
727
+
728
+ .seam-thermostat-climate-presets-card-top {
729
+ display: flex;
730
+ flex-flow: row nowrap;
731
+ align-items: center;
732
+ gap: 8px;
733
+ width: 100%;
734
+ justify-content: space-between;
735
+ border-bottom: 1px solid color.scale(colors.$bg-a, $lightness: -5%);
736
+ padding: 8px;
737
+ background-color: colors.$bg-b;
738
+
739
+ .seam-thermostat-climate-presets-card-name {
740
+ font-size: 16px;
741
+ font-weight: 600;
742
+ line-height: 118%;
743
+ white-space: nowrap;
744
+ }
745
+
746
+ .seam-thermostat-climate-presets-card-name-key {
747
+ font-size: 12px;
748
+ font-weight: 400;
749
+ line-height: 118%;
750
+ white-space: nowrap;
751
+ color: colors.$text-gray-2;
752
+ }
753
+
754
+ .seam-thermostat-climate-presets-card-buttons {
755
+ display: flex;
756
+ flex-flow: row nowrap;
757
+ gap: 4px;
758
+ justify-content: flex-end;
759
+ }
760
+ }
761
+
762
+ .seam-thermostat-climate-presets-card-body {
763
+ display: flex;
764
+ flex-flow: row wrap;
765
+ align-items: center;
766
+ gap: 10px;
767
+ width: 100%;
768
+ padding: 8px;
769
+ justify-content: space-around;
770
+ }
771
+
772
+ .seam-thermostat-climate-preset-chip {
773
+ display: inline-flex;
774
+ flex-flow: row nowrap;
775
+ gap: 4px;
776
+ align-items: center;
777
+ justify-content: space-between;
778
+ width: max-content;
779
+
780
+ .seam-thermostat-climate-preset-chip-icon {
781
+ color: colors.$text-gray-1;
782
+ font-weight: 600;
783
+
784
+ svg {
785
+ position: relative;
786
+ top: 2px;
787
+ }
788
+ }
789
+
790
+ .seam-thermostat-climate-preset-chip-value {
791
+ font-weight: 600;
792
+ }
793
+ }
794
+ }
795
+ }
796
+
797
+ @mixin climate-preset {
798
+ .seam-thermostat-climate-preset {
799
+ @include acf.main;
800
+
801
+ .seam-climate-preset-buttons {
802
+ display: flex;
803
+ flex-flow: row nowrap;
804
+ gap: 8px;
805
+ }
806
+ }
807
+ }
808
+
659
809
  @mixin all {
660
810
  @include climate-setting-control-group;
661
811
  @include temperature-control-group;
@@ -666,4 +816,6 @@
666
816
  @include fan-mode-menu;
667
817
  @include climate-mode-menu;
668
818
  @include status;
819
+ @include climate-presets;
820
+ @include climate-preset;
669
821
  }