@dative-gpi/foundation-shared-components 0.0.206 → 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.
@@ -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.206",
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.206",
14
- "@dative-gpi/foundation-shared-services": "0.0.206"
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": "7ef1a1b0b6a291c09cb136bd597e4f1837415e71"
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;