@fmidev/smartmet-alert-client 4.4.19 → 4.7.0-beta.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 (123) hide show
  1. package/.eslintignore +2 -14
  2. package/.github/workflows/test.yaml +26 -0
  3. package/.nvmrc +1 -0
  4. package/AGENTS.md +26 -0
  5. package/index.html +1 -1
  6. package/package.json +80 -22
  7. package/src/AlertClientVue.vue +160 -0
  8. package/src/App.vue +154 -296
  9. package/src/assets/img/ui/arrow-down.svg +4 -11
  10. package/src/assets/img/ui/arrow-up.svg +4 -11
  11. package/src/assets/img/ui/clear.svg +7 -21
  12. package/src/assets/img/ui/close.svg +4 -15
  13. package/src/assets/img/ui/toggle-selected.svg +5 -6
  14. package/src/assets/img/ui/toggle-unselected.svg +5 -6
  15. package/src/assets/img/warning/cold-weather.svg +3 -6
  16. package/src/assets/img/warning/flood-level-3.svg +4 -7
  17. package/src/assets/img/warning/forest-fire-weather.svg +2 -6
  18. package/src/assets/img/warning/grass-fire-weather.svg +2 -6
  19. package/src/assets/img/warning/hot-weather.svg +3 -6
  20. package/src/assets/img/warning/pedestrian-safety.svg +3 -7
  21. package/src/assets/img/warning/rain.svg +2 -7
  22. package/src/assets/img/warning/sea-icing.svg +2 -6
  23. package/src/assets/img/warning/sea-thunder-storm.svg +2 -5
  24. package/src/assets/img/warning/sea-water-height-high-water.svg +3 -8
  25. package/src/assets/img/warning/sea-water-height-shallow-water.svg +3 -7
  26. package/src/assets/img/warning/sea-wave-height.svg +4 -7
  27. package/src/assets/img/warning/sea-wind-legend.svg +2 -5
  28. package/src/assets/img/warning/sea-wind.svg +2 -5
  29. package/src/assets/img/warning/several.svg +2 -5
  30. package/src/assets/img/warning/thunder-storm.svg +2 -5
  31. package/src/assets/img/warning/traffic-weather.svg +2 -6
  32. package/src/assets/img/warning/uv-note.svg +2 -6
  33. package/src/assets/img/warning/wind.svg +2 -5
  34. package/src/components/AlertClient.vue +330 -251
  35. package/src/components/CollapsiblePanel.vue +281 -0
  36. package/src/components/DayLarge.vue +146 -110
  37. package/src/components/DaySmall.vue +97 -81
  38. package/src/components/Days.vue +229 -159
  39. package/src/components/DescriptionWarning.vue +63 -38
  40. package/src/components/GrayScaleToggle.vue +58 -54
  41. package/src/components/Legend.vue +102 -325
  42. package/src/components/MapLarge.vue +574 -351
  43. package/src/components/MapSmall.vue +137 -122
  44. package/src/components/PopupRow.vue +24 -12
  45. package/src/components/Region.vue +168 -118
  46. package/src/components/RegionWarning.vue +40 -33
  47. package/src/components/Regions.vue +189 -105
  48. package/src/components/Warning.vue +70 -45
  49. package/src/components/Warnings.vue +136 -72
  50. package/src/composables/useAlertClient.ts +360 -0
  51. package/src/composables/useConfig.ts +573 -0
  52. package/src/composables/useFields.ts +66 -0
  53. package/src/composables/useI18n.ts +62 -0
  54. package/src/composables/useKeyCodes.ts +16 -0
  55. package/src/composables/useMapPaths.ts +477 -0
  56. package/src/composables/useUtils.ts +683 -0
  57. package/src/composables/useWarningsProcessor.ts +1007 -0
  58. package/src/data/geometries.json +993 -0
  59. package/src/{main.js → main.ts} +1 -0
  60. package/src/mixins/geojsonsvg.d.ts +57 -0
  61. package/src/mixins/geojsonsvg.js +5 -3
  62. package/src/plugins/index.ts +5 -0
  63. package/src/scss/_utilities.scss +193 -0
  64. package/src/scss/constants.scss +2 -1
  65. package/src/scss/warningImages.scss +8 -3
  66. package/src/types/index.ts +509 -0
  67. package/src/vite-env.d.ts +23 -0
  68. package/src/vue.ts +41 -0
  69. package/svgo.config.js +45 -0
  70. package/tests/README.md +430 -0
  71. package/tests/fixtures/mockWarningData.ts +152 -0
  72. package/tests/integration/warning-flow.spec.ts +445 -0
  73. package/tests/setup.ts +41 -0
  74. package/tests/unit/components/AlertClient.spec.ts +701 -0
  75. package/tests/unit/components/DayLarge.spec.ts +348 -0
  76. package/tests/unit/components/DaySmall.spec.ts +352 -0
  77. package/tests/unit/components/Days.spec.ts +548 -0
  78. package/tests/unit/components/DescriptionWarning.spec.ts +385 -0
  79. package/tests/unit/components/GrayScaleToggle.spec.ts +318 -0
  80. package/tests/unit/components/Legend.spec.ts +295 -0
  81. package/tests/unit/components/MapLarge.spec.ts +448 -0
  82. package/tests/unit/components/MapSmall.spec.ts +367 -0
  83. package/tests/unit/components/PopupRow.spec.ts +270 -0
  84. package/tests/unit/components/Region.spec.ts +373 -0
  85. package/tests/unit/components/RegionWarning.snapshot.spec.ts +361 -0
  86. package/tests/unit/components/RegionWarning.spec.ts +381 -0
  87. package/tests/unit/components/Regions.spec.ts +503 -0
  88. package/tests/unit/components/Warning.snapshot.spec.ts +483 -0
  89. package/tests/unit/components/Warning.spec.ts +489 -0
  90. package/tests/unit/components/Warnings.spec.ts +343 -0
  91. package/tests/unit/components/__snapshots__/RegionWarning.snapshot.spec.ts.snap +41 -0
  92. package/tests/unit/components/__snapshots__/Warning.snapshot.spec.ts.snap +433 -0
  93. package/tests/unit/composables/useConfig.spec.ts +279 -0
  94. package/tests/unit/composables/useI18n.spec.ts +116 -0
  95. package/tests/unit/composables/useKeyCodes.spec.ts +27 -0
  96. package/tests/unit/composables/useUtils.spec.ts +213 -0
  97. package/tsconfig.json +43 -0
  98. package/tsconfig.node.json +11 -0
  99. package/vite.config.js +96 -26
  100. package/vitest.config.js +40 -0
  101. package/dist/favicon.ico +0 -0
  102. package/dist/index.dark.html +0 -20
  103. package/dist/index.en.html +0 -15
  104. package/dist/index.fi.html +0 -15
  105. package/dist/index.html +0 -15
  106. package/dist/index.js +0 -281
  107. package/dist/index.mjs +0 -281
  108. package/dist/index.mjs.map +0 -1
  109. package/dist/index.relative.html +0 -19
  110. package/dist/index.start.html +0 -20
  111. package/dist/index.sv.html +0 -15
  112. package/playwright.config.ts +0 -18
  113. package/public/index.relative.html +0 -19
  114. package/public/index.start.html +0 -20
  115. package/src/mixins/config.js +0 -1378
  116. package/src/mixins/fields.js +0 -26
  117. package/src/mixins/i18n.js +0 -25
  118. package/src/mixins/keycodes.js +0 -10
  119. package/src/mixins/panzoom.js +0 -900
  120. package/src/mixins/utils.js +0 -900
  121. package/src/plugins/index.js +0 -3
  122. package/test/snapshot.test.ts +0 -126
  123. package/vitest.config.ts +0 -6
@@ -9,8 +9,7 @@
9
9
  `level-${input.severity}`,
10
10
  `${typeClass}`,
11
11
  ]"
12
- :aria-label="`${warningLevel} ${warningTypeText}${warningDetails}`"
13
- >
12
+ :aria-label="`${warningLevel} ${warningTypeText}${warningDetails}`">
14
13
  <span
15
14
  aria-hidden="true"
16
15
  :class="[
@@ -23,38 +22,46 @@
23
22
  </div>
24
23
  </template>
25
24
 
26
- <script>
27
- import fields from '../mixins/fields'
28
- import i18n from '../mixins/i18n'
29
- import utils from '../mixins/utils'
25
+ <script setup lang="ts">
26
+ import { computed, toRef } from 'vue'
27
+ import { useFields } from '@/composables/useFields'
28
+ import { useI18n } from '@/composables/useI18n'
29
+ import type { WarningIconInput } from '@/types'
30
30
 
31
- export default {
32
- name: 'RegionWarning',
33
- mixins: [fields, i18n, utils],
34
- props: {
35
- input: {
36
- type: Object,
37
- default: null,
38
- },
39
- language: {
40
- type: String,
41
- },
42
- },
43
- computed: {
44
- warningLevel() {
45
- return this.t(`warningLevel${this.input.severity}`)
46
- },
47
- warningTypeText() {
48
- return this.t(this.input.type).toLowerCase();
49
- },
50
- warningDetails() {
51
- if (this.input.text == null || this.input.direction == null) {
52
- return ''
53
- }
54
- return ` (${this.input.text} m/s ${this.t("fromDirection")} ${this.input.direction + 180}°)`
55
- }
56
- },
57
- }
31
+ // Props
32
+ const props = defineProps<{
33
+ input: WarningIconInput
34
+ language?: string
35
+ }>()
36
+
37
+ // Composables
38
+ const { typeClass, rotation, invertedRotation, severity } = useFields(
39
+ toRef(props, 'input')
40
+ )
41
+ const { t } = useI18n(toRef(props, 'language'))
42
+
43
+ // Expose for testing
44
+ defineExpose({
45
+ severity,
46
+ })
47
+
48
+ // Computed
49
+ const warningLevel = computed((): string => {
50
+ return t(`warningLevel${props.input.severity}`)
51
+ })
52
+
53
+ const warningTypeText = computed((): string => {
54
+ return t(props.input.type).toLowerCase()
55
+ })
56
+
57
+ const warningDetails = computed((): string => {
58
+ if (props.input.text == null || props.input.direction == null) {
59
+ return ''
60
+ }
61
+ return ` (${props.input.text} m/s ${t('fromDirection')} ${
62
+ props.input.direction + 180
63
+ }°)`
64
+ })
58
65
  </script>
59
66
 
60
67
  <style scoped lang="scss">
@@ -1,7 +1,9 @@
1
1
  <template>
2
2
  <div id="region-warnings" class="row">
3
3
  <div v-if="anyLandWarnings" class="region-type-container">
4
- <h3 id="header-land" class="header-region">{{ landText }}</h3>
4
+ <h3 id="header-land" class="header-region">
5
+ {{ landText }}
6
+ </h3>
5
7
  <a
6
8
  id="fmi-warnings-region-content"
7
9
  :href="fromLandToNextContentHref"
@@ -26,7 +28,9 @@
26
28
  </div>
27
29
 
28
30
  <div v-if="anySeaWarnings" class="region-type-container">
29
- <h3 id="header-sea" class="header-region">{{ seaText }}</h3>
31
+ <h3 id="header-sea" class="header-region">
32
+ {{ seaText }}
33
+ </h3>
30
34
  <a
31
35
  :id="fromSeaToNextContentId"
32
36
  href="#fmi-warnings-end-of-regions"
@@ -53,113 +57,193 @@
53
57
  </div>
54
58
  </template>
55
59
 
56
- <script>
57
- import config from '../mixins/config'
58
- import i18n from '../mixins/i18n'
59
- import utils from '../mixins/utils'
60
+ <script setup lang="ts">
61
+ import { computed, toRef, getCurrentInstance } from 'vue'
62
+ import { useI18n } from '@/composables/useI18n'
63
+ import { useConfig } from '@/composables/useConfig'
64
+ import { REGION_LAND, REGION_SEA } from '@/composables/useUtils'
60
65
  import Region from './Region.vue'
66
+ import type {
67
+ RegionsData,
68
+ WarningsMap,
69
+ DayRegions,
70
+ RegionListItem,
71
+ Theme,
72
+ Language,
73
+ } from '@/types'
61
74
 
62
- export default {
63
- name: 'Regions',
64
- components: { Region },
65
- mixins: [config, i18n, utils],
66
- props: {
67
- input: Array,
68
- selectedDay: Number,
69
- warnings: {
70
- type: Object,
71
- default: null,
72
- },
73
- parents: Object,
74
- geometryId: Number,
75
- theme: String,
76
- language: String,
77
- },
78
- computed: {
79
- landText() {
80
- return this.t('regionLand')
81
- },
82
- seaText() {
83
- return this.t('regionSea')
84
- },
85
- fromLandToNextContentText() {
86
- return `${this.t('warningsInAreasStart')} ${
87
- this.t(`in${this.regions.land.length}Areas`)
88
- }. ${this.t('toNextContent')}`
89
- },
90
- fromSeaToNextContentText() {
91
- return `${this.t('warningsInAreasStart')} ${
92
- this.t(`in${this.regions.sea.length}Areas`)
93
- }. ${this.t('toNextContent')}`
94
- },
95
- fromLandToNextContentHref() {
96
- return this.anySeaWarnings
97
- ? '#fmi-warnings-from-sea-to-next-content'
98
- : '#fmi-warnings-end-of-regions'
99
- },
100
- fromSeaToNextContentId() {
101
- return this.anyLandWarnings
102
- ? 'fmi-warnings-from-sea-to-next-content'
103
- : 'fmi-warnings-region-content'
104
- },
105
- regions() {
106
- const compareRegions = (region1, region2) =>
107
- region1.regionIndex - region2.regionIndex
108
- const overriddenRegions = this.parents
109
- const overriddenIds = Object.keys(overriddenRegions).filter(
110
- (regionId) => overriddenRegions[regionId][this.selectedDay]
111
- )
112
- return [this.REGION_LAND, this.REGION_SEA].reduce(
113
- (regionData, regionType) => {
114
- // eslint-disable-next-line no-param-reassign
115
- regionData[regionType] = this.input[this.selectedDay][
116
- regionType
117
- ].reduce((regions, region) => {
118
- const parentId = this.geometries[this.geometryId][region.key].parent
119
- if (
120
- !overriddenIds.includes(region.key) &&
121
- (!parentId || overriddenIds.includes(parentId)) &&
122
- region.warnings.some(
123
- (warning) => warning.coverage >= this.coverageCriterion
124
- )
125
- ) {
126
- regions.push(region)
127
- }
128
- return regions
129
- }, [])
130
- regionData[regionType].sort(compareRegions)
131
- return regionData
132
- },
133
- {}
134
- )
135
- },
136
- anyLandWarnings() {
137
- return this.anyRegionWarnings('land')
138
- },
139
- anySeaWarnings() {
140
- return this.anyRegionWarnings('sea')
141
- },
142
- },
143
- methods: {
144
- anyRegionWarnings(regionType) {
145
- return (
146
- this.regions != null &&
147
- this.regions[regionType] != null &&
148
- this.regions[regionType].length > 0
149
- )
150
- },
151
- fromLandToNextContentClicked() {
152
- const nextContent = this.$el.querySelector(this.fromLandToNextContentHref)
153
- nextContent.scrollIntoView()
154
- nextContent.focus()
155
- },
156
- fromSeaToNextContentClicked() {
157
- const nextContent = this.$el.querySelector('#fmi-warnings-end-of-regions')
158
- nextContent.scrollIntoView()
159
- nextContent.focus()
75
+ // ============================================================================
76
+ // Props
77
+ // ============================================================================
78
+
79
+ const props = withDefaults(
80
+ defineProps<{
81
+ input?: RegionsData
82
+ selectedDay?: number
83
+ warnings?: WarningsMap | null
84
+ parents?: Record<string, boolean[]>
85
+ geometryId?: number
86
+ theme?: Theme | string
87
+ language?: Language
88
+ }>(),
89
+ {
90
+ input: () => [],
91
+ selectedDay: 0,
92
+ warnings: null,
93
+ parents: () => ({}),
94
+ geometryId: 2021,
95
+ theme: 'light-theme',
96
+ language: undefined,
97
+ }
98
+ )
99
+
100
+ // ============================================================================
101
+ // Composables
102
+ // ============================================================================
103
+
104
+ const { t } = useI18n(toRef(() => props.language))
105
+ const { geometries, coverageCriterion } = useConfig()
106
+
107
+ const instance = getCurrentInstance()
108
+
109
+ // ============================================================================
110
+ // Computed Properties
111
+ // ============================================================================
112
+
113
+ const landText = computed<string>(() => {
114
+ return t('regionLand')
115
+ })
116
+
117
+ const seaText = computed<string>(() => {
118
+ return t('regionSea')
119
+ })
120
+
121
+ const fromLandToNextContentText = computed<string>(() => {
122
+ return `${t('warningsInAreasStart')} ${t(
123
+ `in${regions.value.land.length}Areas`
124
+ )}. ${t('toNextContent')}`
125
+ })
126
+
127
+ const fromSeaToNextContentText = computed<string>(() => {
128
+ return `${t('warningsInAreasStart')} ${t(
129
+ `in${regions.value.sea.length}Areas`
130
+ )}. ${t('toNextContent')}`
131
+ })
132
+
133
+ const fromLandToNextContentHref = computed<string>(() => {
134
+ return anySeaWarnings.value
135
+ ? '#fmi-warnings-from-sea-to-next-content'
136
+ : '#fmi-warnings-end-of-regions'
137
+ })
138
+
139
+ const fromSeaToNextContentId = computed<string>(() => {
140
+ return anyLandWarnings.value
141
+ ? 'fmi-warnings-from-sea-to-next-content'
142
+ : 'fmi-warnings-region-content'
143
+ })
144
+
145
+ const regions = computed<DayRegions>(() => {
146
+ const compareRegions = (region1: RegionListItem, region2: RegionListItem) =>
147
+ region1.regionIndex - region2.regionIndex
148
+
149
+ const overriddenRegions = props.parents
150
+ const overriddenIds = Object.keys(overriddenRegions).filter(
151
+ (regionId) => overriddenRegions[regionId]?.[props.selectedDay]
152
+ )
153
+
154
+ const geometryData = geometries[props.geometryId]
155
+
156
+ return [REGION_LAND, REGION_SEA].reduce(
157
+ (regionData, regionType) => {
158
+ const dayData = props.input[props.selectedDay]
159
+ if (!dayData) {
160
+ regionData[regionType as keyof DayRegions] = []
161
+ return regionData
162
+ }
163
+
164
+ regionData[regionType as keyof DayRegions] = dayData[
165
+ regionType as keyof DayRegions
166
+ ].reduce((filteredRegions: RegionListItem[], region) => {
167
+ const regionGeometry = geometryData?.[region.key]
168
+ const parentId =
169
+ regionGeometry && 'parent' in regionGeometry
170
+ ? regionGeometry.parent
171
+ : ''
172
+ if (
173
+ !overriddenIds.includes(region.key) &&
174
+ (!parentId || overriddenIds.includes(parentId)) &&
175
+ region.warnings.some(
176
+ (warning) => warning.coverage >= coverageCriterion
177
+ )
178
+ ) {
179
+ filteredRegions.push(region)
180
+ }
181
+ return filteredRegions
182
+ }, [])
183
+
184
+ regionData[regionType as keyof DayRegions].sort(compareRegions)
185
+ return regionData
160
186
  },
161
- },
187
+ { land: [], sea: [] } as DayRegions
188
+ )
189
+ })
190
+
191
+ const anyLandWarnings = computed<boolean>(() => {
192
+ return anyRegionWarnings('land')
193
+ })
194
+
195
+ const anySeaWarnings = computed<boolean>(() => {
196
+ return anyRegionWarnings('sea')
197
+ })
198
+
199
+ // ============================================================================
200
+ // Methods
201
+ // ============================================================================
202
+
203
+ const anyRegionWarnings = (regionType: 'land' | 'sea'): boolean => {
204
+ return (
205
+ regions.value != null &&
206
+ regions.value[regionType] != null &&
207
+ regions.value[regionType].length > 0
208
+ )
209
+ }
210
+
211
+ const fromLandToNextContentClicked = (): void => {
212
+ const el = instance?.proxy?.$el as HTMLElement | undefined
213
+ const nextContent = el?.querySelector<HTMLElement>(
214
+ fromLandToNextContentHref.value
215
+ )
216
+ nextContent?.scrollIntoView()
217
+ nextContent?.focus()
218
+ }
219
+
220
+ const fromSeaToNextContentClicked = (): void => {
221
+ const el = instance?.proxy?.$el as HTMLElement | undefined
222
+ const nextContent = el?.querySelector<HTMLElement>(
223
+ '#fmi-warnings-end-of-regions'
224
+ )
225
+ nextContent?.scrollIntoView()
226
+ nextContent?.focus()
162
227
  }
228
+
229
+ // ============================================================================
230
+ // Expose for tests
231
+ // ============================================================================
232
+
233
+ defineExpose({
234
+ landText,
235
+ seaText,
236
+ fromLandToNextContentText,
237
+ fromSeaToNextContentText,
238
+ fromLandToNextContentHref,
239
+ fromSeaToNextContentId,
240
+ regions,
241
+ anyLandWarnings,
242
+ anySeaWarnings,
243
+ anyRegionWarnings,
244
+ fromLandToNextContentClicked,
245
+ fromSeaToNextContentClicked,
246
+ })
163
247
  </script>
164
248
 
165
249
  <style scoped lang="scss">
@@ -3,8 +3,7 @@
3
3
  <div class="symbol-list-cell symbol-list-cell-image">
4
4
  <div
5
5
  :class="`level-${severity} ${typeClass} symbol-list-image-column symbol-list-image warning-image`"
6
- :aria-label="`${warningLevelText} ${title.toLowerCase()}`">
7
- </div>
6
+ :aria-label="`${warningLevelText} ${title.toLowerCase()}`"></div>
8
7
  </div>
9
8
  <div class="symbol-list-cell symbol-list-cell-text">
10
9
  <div class="symbol-list-text-select">
@@ -28,10 +27,10 @@
28
27
  @click="toggle"
29
28
  @keydown.enter="toggle"
30
29
  @keydown.space="toggle">
31
- <span>
32
- {{ toggleText }}
33
- </span>
34
- </div>
30
+ <span>
31
+ {{ toggleText }}
32
+ </span>
33
+ </div>
35
34
  </div>
36
35
  </div>
37
36
  <hr />
@@ -39,44 +38,69 @@
39
38
  </div>
40
39
  </template>
41
40
 
42
- <script>
43
- import fields from '../mixins/fields'
44
- import i18n from '../mixins/i18n'
45
- import utils from '../mixins/utils'
46
-
47
- export default {
48
- name: 'Warning',
49
- mixins: [fields, i18n, utils],
50
- props: ['input', 'hideable', 'language', 'theme'],
51
- computed: {
52
- id() {
53
- return `fmi-warnings-flag-${this.input.type}`
54
- },
55
- title() {
56
- return this.t(this.input.type)
57
- },
58
- warningLevelText() {
59
- return this.t(`warningLevel${this.severity}`)
60
- },
61
- toggleText() {
62
- return this.input.visible ? this.t('toggleOn') : this.t('toggleOff')
63
- },
64
- },
65
- methods: {
66
- toggle(event) {
67
- event.preventDefault()
68
- this.setWarningVisibility(!this.input.visible)
69
- },
70
- setWarningVisibility(visible) {
71
- this.$emit('warningToggled', {
72
- warning: this.input.type,
73
- visible,
74
- })
75
- },
76
- preventEvents(event) {
77
- event.preventDefault()
78
- },
79
- },
41
+ <script setup lang="ts">
42
+ import { computed, toRef } from 'vue'
43
+ import { useFields } from '@/composables/useFields'
44
+ import { useI18n } from '@/composables/useI18n'
45
+ import type { LegendItem } from '@/types'
46
+
47
+ // Props
48
+ const props = defineProps<{
49
+ input: LegendItem
50
+ hideable?: boolean
51
+ language?: string
52
+ theme?: string
53
+ }>()
54
+
55
+ // Emits
56
+ const emit = defineEmits<{
57
+ warningToggled: [data: { warning: string; visible: boolean }]
58
+ }>()
59
+
60
+ // Composables
61
+ const { typeClass, rotation, invertedRotation, severity } = useFields(
62
+ toRef(props, 'input')
63
+ )
64
+ const { t } = useI18n(toRef(props, 'language'))
65
+
66
+ // Expose for testing
67
+ defineExpose({
68
+ rotation,
69
+ invertedRotation,
70
+ })
71
+
72
+ // Computed
73
+ const id = computed((): string => {
74
+ return `fmi-warnings-flag-${props.input.type}`
75
+ })
76
+
77
+ const title = computed((): string => {
78
+ return t(props.input.type)
79
+ })
80
+
81
+ const warningLevelText = computed((): string => {
82
+ return t(`warningLevel${severity.value}`)
83
+ })
84
+
85
+ const toggleText = computed((): string => {
86
+ return props.input.visible ? t('toggleOn') : t('toggleOff')
87
+ })
88
+
89
+ // Methods
90
+ function toggle(event: Event): void {
91
+ event.preventDefault()
92
+ setWarningVisibility(!props.input.visible)
93
+ }
94
+
95
+ function setWarningVisibility(visible: boolean): void {
96
+ emit('warningToggled', {
97
+ warning: props.input.type,
98
+ visible,
99
+ })
100
+ }
101
+
102
+ function preventEvents(event: Event): void {
103
+ event.preventDefault()
80
104
  }
81
105
  </script>
82
106
 
@@ -204,6 +228,7 @@ div.symbol-list-text {
204
228
  justify-content: center;
205
229
  width: 100%;
206
230
  height: $symbol-list-select-height;
231
+ cursor: pointer;
207
232
  margin: 0;
208
233
  background-repeat: no-repeat;
209
234
  background-position: center;
@@ -222,7 +247,7 @@ div.symbol-list-text {
222
247
  }
223
248
  }
224
249
  span {
225
- font-family: "Noto Sans", sans-serif;
250
+ font-family: 'Noto Sans', sans-serif;
226
251
  font-size: $font-size;
227
252
  forced-color-adjust: none;
228
253
  }