@dative-gpi/foundation-shared-components 0.0.205 → 0.0.207

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 (31) hide show
  1. package/assets/images/map/imagery.png +0 -0
  2. package/assets/images/map/osm.png +0 -0
  3. package/components/FSCalendar.vue +1 -0
  4. package/components/FSCalendarTwin.vue +2 -1
  5. package/components/FSClock.vue +18 -6
  6. package/components/FSImageCard.vue +72 -0
  7. package/components/autocompletes/FSAutoCompleteAddress.vue +6 -6
  8. package/components/autocompletes/FSAutocompleteLanguage.vue +4 -5
  9. package/components/autocompletes/FSAutocompleteTimeZone.vue +4 -5
  10. package/components/fields/FSColorField.vue +9 -11
  11. package/components/fields/FSDateField.vue +10 -4
  12. package/components/fields/FSDateRangeField.vue +10 -4
  13. package/components/fields/FSDateTimeField.vue +20 -11
  14. package/components/fields/FSDateTimeRangeField.vue +35 -25
  15. package/components/fields/FSRichTextField.vue +132 -54
  16. package/components/fields/FSTermField.vue +190 -186
  17. package/components/fields/FSTimeField.vue +17 -12
  18. package/components/fields/FSTranslateField.vue +7 -14
  19. package/components/fields/FSTranslateRichTextField.vue +185 -0
  20. package/components/map/FSMap.vue +129 -65
  21. package/components/map/FSMapEditPointAddressOverlay.vue +19 -18
  22. package/components/map/FSMapLayerButton.vue +71 -0
  23. package/models/map.ts +1 -0
  24. package/models/richTextVariable.ts +5 -0
  25. package/models/variableNode.ts +105 -0
  26. package/package.json +4 -4
  27. package/styles/components/fs_image_card.scss +18 -0
  28. package/styles/components/fs_map.scss +10 -14
  29. package/styles/components/fs_rich_text_field.scss +16 -4
  30. package/styles/components/index.scss +1 -0
  31. package/utils/lexical.ts +2 -0
@@ -1,8 +1,8 @@
1
1
  <template>
2
2
  <FSCard
3
3
  padding="16px"
4
- width="100%"
5
4
  height="100%"
5
+ width="100%"
6
6
  :elevation="true"
7
7
  >
8
8
  <FSCol
@@ -50,11 +50,11 @@
50
50
  />
51
51
  </FSRow>
52
52
  <FSButton
53
- :label="$tr('ui.map.save', 'Save')"
53
+ prependIcon="mdi-content-save"
54
+ style="display: none;"
54
55
  color="primary"
55
- prepend-icon="mdi-content-save"
56
56
  type="submit"
57
- style="display: none;"
57
+ :label="$tr('ui.map.save', 'Save')"
58
58
  />
59
59
  </FSForm>
60
60
  </FSCol>
@@ -66,9 +66,9 @@
66
66
  @click="onCancel"
67
67
  />
68
68
  <FSButton
69
- :label="$tr('ui.map.save', 'Save')"
69
+ prependIcon="mdi-content-save"
70
70
  color="primary"
71
- prepend-icon="mdi-content-save"
71
+ :label="$tr('ui.map.save', 'Save')"
72
72
  @click="onSubmit"
73
73
  />
74
74
  </FSRow>
@@ -104,17 +104,16 @@ export default defineComponent({
104
104
  },
105
105
  props: {
106
106
  modelValue: {
107
- type: Object as PropType<Address>,
108
- default: null,
109
- required: false,
107
+ type: Object as PropType<Address | null>,
108
+ default: null
110
109
  }
111
110
  },
112
111
  emits: ["update:modelValue", "update:locationCoordinates", "submit", "cancel"],
113
112
  setup(props, { emit }) {
114
113
  const menuLocationCoordinates = ref(false);
115
114
 
116
- const latitude = ref(props.modelValue.latitude);
117
- const longitude = ref(props.modelValue.longitude);
115
+ const latitude = ref(0);
116
+ const longitude = ref(0);
118
117
 
119
118
  const onCoordinatesChange = () => {
120
119
  const newModelValue = new Address({
@@ -130,7 +129,7 @@ export default defineComponent({
130
129
  };
131
130
 
132
131
  const onAddressFieldSubmit = (address: Address|null) => {
133
- if(address === null) {
132
+ if(!address) {
134
133
  return;
135
134
  }
136
135
  emit('update:modelValue', address);
@@ -144,10 +143,12 @@ export default defineComponent({
144
143
  emit('cancel');
145
144
  };
146
145
 
147
- watch(() => props.modelValue, (value) => {
148
- latitude.value = value.latitude;
149
- longitude.value = value.longitude;
150
- });
146
+ watch(() => props.modelValue, () => {
147
+ if (props.modelValue) {
148
+ latitude.value = props.modelValue.latitude;
149
+ longitude.value = props.modelValue.longitude;
150
+ }
151
+ }, { immediate: true });
151
152
 
152
153
  return {
153
154
  menuLocationCoordinates,
@@ -155,8 +156,8 @@ export default defineComponent({
155
156
  latitude,
156
157
  onAddressFieldSubmit,
157
158
  onCoordinatesChange,
158
- onSubmit,
159
- onCancel
159
+ onCancel,
160
+ onSubmit
160
161
  };
161
162
  }
162
163
  });
@@ -0,0 +1,71 @@
1
+ <template>
2
+ <FSButton
3
+ prependIcon="mdi-layers-outline"
4
+ :elevation="true"
5
+ @click="dialog = true"
6
+ />
7
+ <FSDialog
8
+ v-model="dialog"
9
+ title="Select Layers"
10
+ width="460px"
11
+ >
12
+ <template
13
+ v-slot:body
14
+ >
15
+ <FSImageCard
16
+ v-for="layer in layers"
17
+ :variant="modelValue === layer.name ? 'full' : 'background'"
18
+ :color="modelValue === layer.name ? 'primary' : 'light'"
19
+ :label="layer.label"
20
+ :src="layer.image"
21
+ :key="layer.name"
22
+ @click="onLayerClick(layer.name)"
23
+ />
24
+ </template>
25
+ </FSDialog>
26
+ </template>
27
+
28
+ <script lang="ts">
29
+ import { defineComponent, type PropType, ref } from "vue";
30
+
31
+ import { type MapLayer } from "../../models";
32
+
33
+ import FSImageCard from "../FSImageCard.vue";
34
+ import FSButton from "../FSButton.vue";
35
+ import FSDialog from "../FSDialog.vue";
36
+
37
+ export default defineComponent({
38
+ name: "FSMapLayerButton",
39
+ components: {
40
+ FSImageCard,
41
+ FSButton,
42
+ FSDialog
43
+ },
44
+ props: {
45
+ layers: {
46
+ type: Array as PropType<MapLayer[]>,
47
+ required: false,
48
+ default: () => []
49
+ },
50
+ modelValue: {
51
+ type: String,
52
+ required: false,
53
+ default: ""
54
+ }
55
+ },
56
+ emits: ["update:modelValue"],
57
+ setup(_, { emit }) {
58
+ const dialog = ref(false);
59
+
60
+ const onLayerClick = (layer: string) => {
61
+ emit("update:modelValue", layer);
62
+ dialog.value = false;
63
+ };
64
+
65
+ return {
66
+ dialog,
67
+ onLayerClick
68
+ };
69
+ }
70
+ });
71
+ </script>
package/models/map.ts CHANGED
@@ -5,6 +5,7 @@ import { type Address } from "@dative-gpi/foundation-shared-domain/models";
5
5
  export interface MapLayer {
6
6
  name : string;
7
7
  label: string;
8
+ image: string;
8
9
  layer: Layer;
9
10
  }
10
11
 
@@ -0,0 +1,5 @@
1
+ export interface RichTextVariable {
2
+ code: string;
3
+ defaultValue: string;
4
+ typeName: string;
5
+ }
@@ -0,0 +1,105 @@
1
+ import { type LexicalNode, DecoratorNode, type SerializedLexicalNode, type Spread, type EditorConfig, type LexicalEditor } from "lexical";
2
+ import type { RichTextVariable } from "./richTextVariable";
3
+
4
+ export type SerializedVariableNode = Spread<
5
+ {
6
+ type: "variable";
7
+ code: string;
8
+ defaultValue: string;
9
+ typeName: string;
10
+ },
11
+ SerializedLexicalNode
12
+ >;
13
+
14
+ export class VariableNode extends DecoratorNode<Element> {
15
+ __code: string;
16
+ __defaultValue: string;
17
+ __typeName: string;
18
+ readonlyMode: boolean;
19
+
20
+ static getType() {
21
+ return "variable";
22
+ }
23
+
24
+ static clone(node: VariableNode) {
25
+ return new VariableNode(node.__code, node.__defaultValue, node.__typeName, node.__key);
26
+ }
27
+
28
+ constructor(code: string, defaultValue: string, typeName: string, key?: string) {
29
+ super(key);
30
+ this.__code = code;
31
+ this.__defaultValue = defaultValue;
32
+ this.__typeName = typeName;
33
+ this.readonlyMode = false;
34
+ }
35
+
36
+ getValue(editorElement: HTMLElement): any {
37
+ const variableValues = editorElement.dataset.variableValues;
38
+ if (!variableValues) { return this.__defaultValue; }
39
+ const values = JSON.parse(variableValues);
40
+ return values[this.__code] ?? this.__defaultValue;
41
+ }
42
+
43
+ createDOM(_config: EditorConfig, _editor: LexicalEditor) {
44
+ const readonlyMode = _editor._rootElement?.dataset.readonly === "true" || false;
45
+
46
+ const container = document.createElement("span");
47
+ container.classList.add("fs-richtextfield-node-variable");
48
+
49
+ const content = document.createElement("span");
50
+ if (readonlyMode) {
51
+ content.classList.add("fs-rich-text-field-node-variable-value");
52
+ if (_editor._rootElement) {
53
+ content.textContent = this.getValue(_editor._rootElement);
54
+ } else {
55
+ content.textContent = this.__defaultValue;
56
+ }
57
+ } else {
58
+ content.classList.add("fs-rich-text-field-node-variable-code");
59
+ content.textContent = `{${this.__code}}`
60
+ }
61
+ container.appendChild(content);
62
+ return container;
63
+ }
64
+
65
+ updateDOM(): boolean {
66
+ return false;
67
+ }
68
+
69
+ exportJSON(): SerializedVariableNode {
70
+ return {
71
+ type: "variable",
72
+ version: 1,
73
+ code: this.__code,
74
+ defaultValue: this.__defaultValue,
75
+ typeName: this.__typeName,
76
+ };
77
+ }
78
+
79
+ decorate(editor: LexicalEditor, config: EditorConfig): Element {
80
+ return this.createDOM(config, editor);
81
+ }
82
+
83
+ static importJSON(serializedNode: SerializedVariableNode): VariableNode {
84
+ return new VariableNode(
85
+ serializedNode.code,
86
+ serializedNode.defaultValue,
87
+ serializedNode.typeName
88
+ );
89
+ }
90
+ }
91
+
92
+ export function $createVariableNode(code: string, defaultValue: string, typeName: string): VariableNode {
93
+ return new VariableNode(code, defaultValue, typeName);
94
+ }
95
+
96
+ export function $modifyVariableNode(node: VariableNode, newValue: RichTextVariable): VariableNode {
97
+ node.__code = newValue.code;
98
+ node.__defaultValue = newValue.defaultValue;
99
+ node.__typeName = newValue.typeName;
100
+ return node;
101
+ }
102
+
103
+ export function $isVariableNode(node: LexicalNode | null | undefined): node is VariableNode {
104
+ return node instanceof VariableNode;
105
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dative-gpi/foundation-shared-components",
3
3
  "sideEffects": false,
4
- "version": "0.0.205",
4
+ "version": "0.0.207",
5
5
  "description": "",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -10,8 +10,8 @@
10
10
  "author": "",
11
11
  "license": "ISC",
12
12
  "dependencies": {
13
- "@dative-gpi/foundation-shared-domain": "0.0.205",
14
- "@dative-gpi/foundation-shared-services": "0.0.205"
13
+ "@dative-gpi/foundation-shared-domain": "0.0.207",
14
+ "@dative-gpi/foundation-shared-services": "0.0.207"
15
15
  },
16
16
  "peerDependencies": {
17
17
  "@dative-gpi/bones-ui": "^0.0.75",
@@ -35,5 +35,5 @@
35
35
  "sass": "1.71.1",
36
36
  "sass-loader": "13.3.2"
37
37
  },
38
- "gitHead": "5921db5434ded466e46ff785f53b082fcb5aa4ce"
38
+ "gitHead": "1387dbf5d3b11c281c0e6183ab900e47c9622a9a"
39
39
  }
@@ -0,0 +1,18 @@
1
+ .fs-image-card {
2
+ > .fs-card {
3
+ background-image: var(--fs-image-card-background);
4
+ background-size: 100%;
5
+ background-position: center;
6
+ }
7
+
8
+ .fs-image-card-label {
9
+ background-color: #0000009d;
10
+ color: white;
11
+ }
12
+ }
13
+
14
+ .fs-image-card:hover {
15
+ > .fs-card {
16
+ background-size: 105%;
17
+ }
18
+ }
@@ -9,21 +9,12 @@
9
9
  filter: grayscale(var(--fs-map-container-grayscale));
10
10
  }
11
11
 
12
- .fs-map-overlay-layer-choice {
12
+ .fs-map-overlay-left {
13
13
  position: absolute;
14
14
  top: 0;
15
15
  left: 0;
16
16
  z-index: 950;
17
17
  margin: 8px;
18
-
19
- >* {
20
- opacity: 0.7;
21
- transition: opacity 0.28s cubic-bezier(0.4, 0, 0.2, 1);
22
- }
23
-
24
- >*:hover {
25
- opacity: 1;
26
- }
27
18
  }
28
19
 
29
20
  .fs-map-overlay-edit-button {
@@ -34,10 +25,17 @@
34
25
  margin: 8px;
35
26
  }
36
27
 
37
- .fs-map-overlay-container {
28
+ .fs-map-overlay-right-top {
29
+ position: absolute;
30
+ top: 0;
31
+ right: 0;
32
+ margin: 4px 8px;
33
+ }
34
+
35
+ .fs-map-overlay-right-bottom {
38
36
  position: absolute;
39
37
  bottom: 0;
40
- left: 0;
38
+ right: 0;
41
39
  z-index: 1000;
42
40
  margin: 4px 8px;
43
41
  width: calc(100% - 16px);
@@ -61,8 +59,6 @@
61
59
  border-top-right-radius: 0 !important;
62
60
 
63
61
  border-top: solid 1px var(--fs-card-border-color) !important;
64
-
65
-
66
62
  }
67
63
  }
68
64
  }
@@ -1,19 +1,31 @@
1
1
  .fs-rich-text-field {
2
2
  width: 100%;
3
3
  min-width: 120px;
4
- outline: none !important;
5
4
  border: 1px solid var(--fs-rich-text-field-border-color) !important;
6
5
  border-radius: 4px !important;
7
6
 
8
- min-height: var(--fs-rich-text-field-min-height);
9
- color: var(--fs-rich-text-field-color);
7
+
10
8
  margin: 2px 2px 2px 0 !important;
11
9
 
10
+ .fs-rich-text-field-content {
11
+ color: var(--fs-rich-text-field-color);
12
+ width: 100%;
13
+ min-height: var(--fs-rich-text-field-min-height);
14
+ outline: none !important;
15
+ }
16
+
17
+ .fs-richtextfield-node-variable {
18
+ .fs-rich-text-field-node-variable-code {
19
+ background-color: var(--fs-rich-text-field-variable-backgroundcolor);
20
+ color: var(--fs-rich-text-field-variable-color);
21
+ border-radius: 4px;
22
+ }
23
+ }
12
24
 
13
25
  &:focus-within {
14
26
  border-color: var(--fs-rich-text-field-active-border-color) !important;
15
27
  }
16
-
28
+
17
29
  @include web {
18
30
  padding: 10px 12px !important;
19
31
  }
@@ -31,6 +31,7 @@
31
31
  @import "fs_icon_field.scss";
32
32
  @import "fs_icon.scss";
33
33
  @import "fs_image.scss";
34
+ @import "fs_image_card.scss";
34
35
  @import "fs_label.scss";
35
36
  @import "fs_link.scss";
36
37
  @import "fs_load_data_table.scss";
package/utils/lexical.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { ElementNode, LexicalNode, RangeSelection, TextNode } from "lexical";
2
2
  import { $isAtNodeEnd } from "@lexical/selection";
3
3
 
4
+ export const emptyLexicalState = "{\"root\":{\"children\":[{\"children\":[],\"direction\":null,\"format\":\"\",\"indent\":0,\"type\":\"paragraph\",\"version\":1}],\"direction\":null,\"format\":\"\",\"indent\":0,\"type\":\"root\",\"version\":1}}";
5
+
4
6
  export const getSelectedNode = (selection: RangeSelection): ElementNode | TextNode => {
5
7
  const anchor = selection.anchor;
6
8
  const focus = selection.focus;