svedit 0.3.0 → 0.4.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.
package/README.md CHANGED
@@ -39,7 +39,7 @@ Now make it your own. The next thing you probably want to do is define your own
39
39
 
40
40
  **Chromeless canvas:** We keep the canvas chromeless, meaning there's no UI elements like toolbars or menus mingled with the content. You can interact with text directly, but everything else happens via tools are shown in separate overlays or in the fixed toolbar.
41
41
 
42
- **Convention over configuration:** We use conventions and assumptions to reduce configuration code and limit the number of ways something can go wrong. For instance, we assume that a node with a property named `content` of type `string` or `annotated_string` is considered kind `text`, while all other nodes are considered kind `node`. Text nodes have special behavior in the system for editing (e.g. they can be splitted and joined).
42
+ **Convention over configuration:** We use conventions and assumptions to reduce configuration code and limit the number of ways something can go wrong. For instance, we assume that a node with a property named `content` of type `annotated_text` is considered kind `text`, while all other nodes are considered kind `node`. Text nodes have special behavior in the system for editing (e.g. they can be splitted and joined).
43
43
 
44
44
  **White-box library:** We expose the internals of the library to allow you to customize and extend it to your needs. That means a little bit more work upfront, but in return lets you control "everything" — the toolbar, the overlays, or how fast the node cursor blinks.
45
45
 
@@ -63,7 +63,7 @@ Properties of nodes can hold values:
63
63
  - `string_array`: An array of good old JavaScript strings
64
64
  - `integer_array`: An array of integers
65
65
  - `number_array`: An array of numbers
66
- - `annotated_string`: a plain text string, but with annotations (bold, italic, link etc.)
66
+ - `annotated_text`: a plain text string, but with annotations (bold, italic, link etc.)
67
67
 
68
68
  Or references:
69
69
  - `node`: References a single node (e.g. an image node can reference a global asset node)
@@ -73,35 +73,53 @@ Or references:
73
73
  ```js
74
74
  const document_schema = {
75
75
  page: {
76
- body: {
77
- type: 'node_array',
78
- node_types: ['nav', 'paragraph', 'list'],
79
- default_node_type: 'paragraph',
76
+ kind: 'document',
77
+ properties: {
78
+ body: {
79
+ type: 'node_array',
80
+ node_types: ['nav', 'paragraph', 'list'],
81
+ default_node_type: 'paragraph',
82
+ }
80
83
  }
81
84
  },
82
85
  paragraph: {
83
- content: { type: 'annotated_string' }
86
+ kind: 'text',
87
+ properties: {
88
+ content: { type: 'annotated_text', allow_newlines: true }
89
+ }
84
90
  },
85
91
  list_item: {
86
- content: { type: 'annotated_string' },
92
+ kind: 'text',
93
+ properties: {
94
+ content: { type: 'annotated_text', allow_newlines: true },
95
+ }
87
96
  },
88
97
  list: {
89
- list_items: {
90
- type: 'node_array',
91
- node_types: ['list_item'],
92
- default_node_type: 'list_item',
98
+ kind: 'block',
99
+ properties: {
100
+ list_items: {
101
+ type: 'node_array',
102
+ node_types: ['list_item'],
103
+ default_node_type: 'list_item',
104
+ }
93
105
  }
94
106
  },
95
107
  nav: {
96
- nav_items: {
97
- type: 'node_array',
98
- node_types: ['nav_item'],
99
- default_node_type: 'nav_item',
108
+ kind: 'block',
109
+ properties: {
110
+ nav_items: {
111
+ type: 'node_array',
112
+ node_types: ['nav_item'],
113
+ default_node_type: 'nav_item',
114
+ }
100
115
  }
101
116
  },
102
117
  nav_item: {
103
- url: { type: 'string' },
104
- label: { type: 'string' },
118
+ kind: 'block',
119
+ properties: {
120
+ url: { type: 'string' },
121
+ label: { type: 'string' },
122
+ }
105
123
  }
106
124
  };
107
125
  ```
@@ -192,7 +210,7 @@ const document_config = {
192
210
  // Custom functions to insert new "blank" nodes and setting the selection
193
211
  // depending on the intended behavior.
194
212
  inserters: {
195
- text: function(tr, content = ['', []], layout = 1) {
213
+ text: function(tr, content = {text: '', annotations: []}, layout = 1) {
196
214
  const new_text = {
197
215
  id: nanoid(),
198
216
  type: 'text',
@@ -276,7 +294,7 @@ Selections are at the heart of Svedit. There are just three types of selections:
276
294
  }
277
295
  ```
278
296
 
279
- You can access the current selection through `doc.selection` anytime. And you can programmatically set the selection using `doc.set_selection(new_selection)`.
297
+ You can access the current selection through `doc.selection` anytime. And you can programmatically set the selection using `doc.selection = new_selection`.
280
298
 
281
299
  ## Rendering
282
300
 
@@ -320,7 +338,7 @@ a simplified version of the markup of `<NodeCursorTrap>` and why it is implement
320
338
  Further things to consider:
321
339
 
322
340
  - If you make a sub-tree `contenteditable="false"`, be aware that you can't create a `contenteditable="true"` segment somewhere inside it. Svedit can only work reliably when there's one contenteditable="true" at root (it's set by `<Svedit`>)
323
- - `<AnnotatedString>` and `<CustomProperty>` must not be wrapped in `contenteditable="false"` to work properly.
341
+ - `<AnnotatedTextProperty>` and `<CustomProperty>` must not be wrapped in `contenteditable="false"` to work properly.
324
342
  - Never apply `position: relative` to the direct parent of `<AnnotatedTextProperty>`, it will cause a [weird Safari bug](https://bsky.app/profile/michaelaufreiter.com/post/3lxvdqyxc622s) to destroy the DOM.
325
343
  - Never use an `<a>` tag inside a `contenteditable="true"` element, as it will cause unexpected behavior. Make it a `<div>` while editing, and an `<a>` in read-only mode.
326
344
 
@@ -1,12 +1,12 @@
1
1
  <script>
2
2
  import { getContext } from 'svelte';
3
- import { char_slice, get_char_length } from './util.js';
3
+ import { char_slice, get_char_length, snake_to_pascal } from './util.js';
4
4
 
5
- /** @import { AnnotatedStringPropertyProps, Annotation, AnnotationFragment } from './types.d.ts'; */
5
+ /** @import { AnnotatedTextPropertyProps, Annotation, AnnotationFragment } from './types.d.ts'; */
6
6
 
7
7
  const svedit = getContext('svedit');
8
8
 
9
- /** @type {AnnotatedStringPropertyProps} */
9
+ /** @type {AnnotatedTextPropertyProps} */
10
10
  let {
11
11
  path,
12
12
  class: css_class,
@@ -20,32 +20,36 @@
20
20
  /**
21
21
  * Converts text with annotations into renderable fragments for display.
22
22
  * @param {string} text - The plain text content
23
- * @param {Array<Annotation>} annotations - Array of annotations where each is [start_offset, end_offset, type, options?] (minimum 3 elements)
23
+ * @param {Array<Annotation>} annotations - Array of annotations where each is {start_offset, end_offset, node_id}
24
24
  * @returns {Array<string|AnnotationFragment>} Array of fragments - strings for plain text, AnnotationFragment objects for annotated content
25
25
  */
26
- function render_annotated_string(text, annotations) {
26
+ function get_fragments(text, annotations) {
27
27
  let fragments = [];
28
28
  let last_index = 0;
29
29
 
30
30
  // Sort annotations by start_offset
31
- const sorted_annotations = [...annotations].sort((a, b) => a[0] - b[0]);
31
+ const sorted_annotations = [...annotations].sort((a, b) => a.start_offset - b.start_offset);
32
32
 
33
- for (let [index, annotation] of sorted_annotations.entries()) {
33
+ for (let [, annotation] of sorted_annotations.entries()) {
34
34
  // Add text before the annotation using character-aware slicing
35
- if (annotation[0] > last_index) {
36
- fragments.push(char_slice(text, last_index, annotation[0]));
35
+ if (annotation.start_offset > last_index) {
36
+ fragments.push(char_slice(text, last_index, annotation.start_offset));
37
37
  }
38
38
 
39
39
  // Add the annotated string using character-aware slicing
40
- const annotated_content = char_slice(text, annotation[0], annotation[1]);
40
+ const annotated_content = char_slice(text, annotation.start_offset, annotation.end_offset);
41
+ const node = svedit.doc.get(annotation.node_id);
42
+ if (!node) throw new Error(`Node not found for annotation ${annotation.node_id}`);
43
+
41
44
  fragments.push({
42
- type: annotation[2],
45
+ node,
43
46
  content: annotated_content,
44
- annotation_index: index,
45
- data: annotation[3]
47
+ // NOTE: We need to provide the original index here, because the source data
48
+ // is the address space.
49
+ annotation_index: annotations.indexOf(annotation),
46
50
  });
47
51
 
48
- last_index = annotation[1];
52
+ last_index = annotation.end_offset;
49
53
  }
50
54
 
51
55
  // Add any remaining text after the last annotation using character-aware slicing
@@ -56,15 +60,9 @@
56
60
  return fragments;
57
61
  }
58
62
 
59
- let fragments = $derived(render_annotated_string(svedit.doc.get(path)[0], svedit.doc.get(path)[1]));
60
- let plain_text = $derived(svedit.doc.get(path)[0]);
63
+ let fragments = $derived(get_fragments(svedit.doc.get(path).text, svedit.doc.get(path).annotations));
64
+ let plain_text = $derived(svedit.doc.get(path).text);
61
65
 
62
- /**
63
- * @param {MouseEvent} e - The click event
64
- */
65
- function handle_link_click(e) {
66
- e.preventDefault();
67
- }
68
66
  </script>
69
67
 
70
68
  {#key plain_text}
@@ -79,21 +77,10 @@
79
77
  placeholder={placeholder}
80
78
  >
81
79
  {#each fragments as fragment, index (index)}
82
- {#if typeof fragment === 'string'}<!--
83
- -->{fragment}<!--
84
- -->{:else if fragment.type === 'emphasis'}<!--
85
- --><em>{fragment.content}</em><!--
86
- -->{:else if fragment.type === 'strong'}<!--
87
- --><strong>{fragment.content}</strong><!--
88
- -->{:else if fragment.type === 'link'}<!--
89
- --><a
90
- onclick={handle_link_click}
91
- style="anchor-name: --{path.join('-') + '-' + fragment.annotation_index};"
92
- href={fragment.data.href}
93
- target={fragment.data.target || '_self'}>{fragment.content}</a><!--
94
- -->{:else}<!--
95
- -->{fragment.content}<!--
96
- -->{/if}
80
+ {#if typeof fragment === 'string'}{fragment}{:else}
81
+ {@const AnnotationComponent = svedit.doc.config.node_components[snake_to_pascal(fragment.node.type)]}
82
+ <AnnotationComponent path={[...path, 'annotations', fragment.annotation_index, 'node_id']} content={fragment.content} />
83
+ {/if}
97
84
  {/each}<!--
98
85
  --><br>
99
86
  </div>
@@ -118,12 +105,13 @@
118
105
 
119
106
  /* We can safely hide the <br> element when the placeholder is empty and focused. */
120
107
  /* No longer the cursor will be rendered after the placeholder when focused. */
108
+ /* ATTENTION: This hack has the side effect that in Safari Desktop the cursor sometimes disappears. */
121
109
  [placeholder].empty.focused br {
122
110
  display:none;
123
111
  }
124
112
 
125
- .text.focused {
113
+ /*.text.focused {
126
114
  background: none;
127
- outline: 1px dashed var(--editing-stroke-color);
128
- }
115
+ outline: 1px solid var(--editing-stroke-color);
116
+ }*/
129
117
  </style>
@@ -0,0 +1,7 @@
1
+ export default AnnotatedTextProperty;
2
+ type AnnotatedTextProperty = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<AnnotatedTextPropertyProps>): void;
5
+ };
6
+ declare const AnnotatedTextProperty: import("svelte").Component<import("./types.d.ts").AnnotatedTextPropertyProps, {}, "">;
7
+ //# sourceMappingURL=AnnotatedTextProperty.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnnotatedTextProperty.svelte.d.ts","sourceRoot":"","sources":["../src/lib/AnnotatedTextProperty.svelte.js"],"names":[],"mappings":";;;;;AAyFA,2HAAoE"}
@@ -8,6 +8,10 @@
8
8
  * DocumentSchemaPrimitive,
9
9
  * NodeProperty,
10
10
  * NodeArrayProperty,
11
+ * NodeKind,
12
+ * NodeSchema,
13
+ * TextNodeSchema,
14
+ * NonTextNodeSchema,
11
15
  * DocumentSchema,
12
16
  * SerializedDocument
13
17
  * } from './types.d.ts';
@@ -16,13 +20,11 @@
16
20
  * Identity function — keeps schema at runtime & makes IDE infer types.
17
21
  * Similar to your define_schema pattern but for document schemas.
18
22
  *
19
- * @template {Record<string, Record<string, {type: DocumentSchemaPrimitive}>>} S
23
+ * @template {Record<string, NodeSchema>} S
20
24
  * @param {S} schema - The document schema to validate
21
25
  * @returns {S} The same schema, but with type information preserved
22
26
  */
23
- export function define_document_schema<S extends Record<string, Record<string, {
24
- type: DocumentSchemaPrimitive;
25
- }>>>(schema: S): S;
27
+ export function define_document_schema<S extends Record<string, NodeSchema>>(schema: S): S;
26
28
  /**
27
29
  * Check if a string represents a valid primitive type.
28
30
  * @param {string} type - The type string to check
@@ -53,8 +55,6 @@ export default class Document {
53
55
  selection?: Selection;
54
56
  config?: any;
55
57
  });
56
- /** @type {Selection | undefined} */
57
- selection: Selection | undefined;
58
58
  config: any;
59
59
  document_id: any;
60
60
  nodes: any;
@@ -63,9 +63,32 @@ export default class Document {
63
63
  can_undo: boolean;
64
64
  can_redo: boolean;
65
65
  selected_node: any;
66
+ layout_node: any;
67
+ available_annotation_types: any;
68
+ /**
69
+ * Sets the selection with validation
70
+ * @param {Selection | undefined} value - The new selection
71
+ * @throws {Error} Throws if the selection is invalid
72
+ */
73
+ set selection(value: Selection | undefined);
74
+ /**
75
+ * Gets the current selection
76
+ * @returns {Selection | undefined}
77
+ */
78
+ get selection(): Selection | undefined;
79
+ /**
80
+ * Validates that a selection is within bounds and refers to valid paths.
81
+ *
82
+ * @param {Selection} selection - The selection to validate
83
+ * @throws {Error} Throws if the selection is invalid
84
+ * @private
85
+ */
86
+ private _validate_selection;
66
87
  schema: DocumentSchema;
67
88
  generate_id(): any;
89
+ get_available_annotation_types(): any;
68
90
  get_selected_node(): any;
91
+ get_layout_node(): any;
69
92
  _apply_op(op: any): void;
70
93
  /**
71
94
  * Validate a node against the document schema.
@@ -104,8 +127,8 @@ export default class Document {
104
127
  * doc.get(['page_1', 'body', 3, 'list_items', 0]) // => { type: 'list_item', id: 'list_item_1', ... }
105
128
  *
106
129
  * @example
107
- * // Get an annotated string property
108
- * doc.get(['page_1', 'cover', 'title']) // => ['Hello world', []]
130
+ * // Get an annotated text property
131
+ * doc.get(['page_1', 'cover', 'title']) // => {text: 'Hello world', annotations: []}
109
132
  */
110
133
  get(path: DocumentPath | string): any;
111
134
  /**
@@ -139,12 +162,12 @@ export default class Document {
139
162
  [key: string]: any;
140
163
  };
141
164
  /**
142
- * Determines the kind of a node ('text' for pure text nodes or 'node' for anything else)
143
- * NOTE: currently we assume a 'content' property for pure text nodes
165
+ * Determines the kind of a node ('block' for structured blocks, 'text' for pure
166
+ * text nodes or 'annotation' for annotation nodes.
144
167
  * @param {any} node
145
- * @returns {'text'|'node'}
168
+ * @returns {NodeKind}
146
169
  */
147
- kind(node: any): "text" | "node";
170
+ kind(node: any): NodeKind;
148
171
  /**
149
172
  * Returns the annotation object that is currently "under the cursor".
150
173
  * NOTE: Annotations in Svedit are exclusive, so there can only be one active_annotation
@@ -155,8 +178,6 @@ export default class Document {
155
178
  active_annotation(annotation_type: string): Annotation | null;
156
179
  get_selected_plain_text(): string;
157
180
  get_selected_nodes(): any;
158
- move_node_cursor(direction: any): void;
159
- expand_node_selection(direction: any): void;
160
181
  select_parent(): void;
161
182
  get_selection_range(): {
162
183
  start: number;
@@ -169,15 +190,16 @@ export default class Document {
169
190
  * @returns {SerializedDocument} The serialized document array
170
191
  */
171
192
  to_json(): SerializedDocument;
172
- property_type(type: any, property: any): "string" | "number" | "boolean" | "node" | "node_array" | "integer" | "datetime" | "string_array" | "number_array" | "boolean_array" | "integer_array" | "annotated_string";
193
+ property_type(type: any, property: any): "string" | "number" | "boolean" | "node" | "node_array" | "annotated_text" | "integer" | "datetime" | "string_array" | "number_array" | "boolean_array" | "integer_array";
173
194
  count_references(node_id: any): number;
174
195
  /**
175
196
  * @param {NodeId} node_id
176
197
  * @returns {NodeId[]}
177
198
  */
178
199
  get_referenced_nodes(node_id: NodeId): NodeId[];
200
+ #private;
179
201
  }
180
- import type { DocumentSchemaPrimitive } from './types.d.ts';
202
+ import type { NodeSchema } from './types.d.ts';
181
203
  import type { PrimitiveType } from './types.d.ts';
182
204
  import type { NodeProperty } from './types.d.ts';
183
205
  import type { NodeArrayProperty } from './types.d.ts';
@@ -185,6 +207,7 @@ import type { DocumentSchema } from './types.d.ts';
185
207
  import type { Selection } from './types.d.ts';
186
208
  import Transaction from './Transaction.svelte.js';
187
209
  import type { DocumentPath } from './types.d.ts';
210
+ import type { NodeKind } from './types.d.ts';
188
211
  import type { Annotation } from './types.d.ts';
189
212
  import type { SerializedDocument } from './types.d.ts';
190
213
  import type { NodeId } from './types.d.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"Document.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Document.svelte.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;GAOG;AACH,uCAJ+E,CAAC,SAAlE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAC,IAAI,EAAE,uBAAuB,CAAA;CAAC,CAAC,CAAE,UACnE,CAAC,GACC,CAAC,CAIb;AAED;;;;GAIG;AACH,wCAHW,MAAM,GACJ,IAAI,IAAI,aAAa,CAQjC;AAED;;;;GAIG;AACH,2DAHW,YAAY,GAAG,iBAAiB,GAC9B,MAAM,GAAG,IAAI,CASzB;AAED;;;;GAIG;AACH,0DAHW,cAAc,QAexB;AAuGD;IAgBE;;;;;;OAMG;IACH,oBANW,cAAc,kBACd,kBAAkB,0BAE1B;QAA4B,SAAS,GAA7B,SAAS;QACK,MAAM,GAApB,GAAG;KACb,EAmBA;IAxCD,oCAAoC;IACpC,WADW,SAAS,GAAG,SAAS,CACX;IACrB,YAAkB;IAClB,iBAAuB;IACvB,WAAiB;IACjB,eAAqB;IACrB,sBAA2B;IAG3B,kBAA6C;IAC7C,kBAAkE;IAGnE,mBAAmD;IAahD,uBAAoB;IAgBtB,mBAMC;IAGF,yBAkBC;IAGA,yBAWC;IAED;;;;OAIG;IACH,oBAHW,GAAG,QAKb;IAED;;;;OAIG;IACH,UAFa,WAAW,CASvB;IAED;;;;OAIG;IACH,mBAFW,WAAW,QAkBrB;IAED,aAWC;IAED,aAaC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,UAlBW,YAAY,GAAC,MAAM,GACjB,GAAG,CAuDf;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,cAHW,YAAY,GACV;QAAC,IAAI,EAAE,UAAU,GAAC,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAC,CAuBzD;IAED;;;;;OAKG;IACH,WAHW,GAAG,GACD,MAAM,GAAC,MAAM,CAQzB;IAED;;;;;;OAMG;IACH,mCAHW,MAAM,GACJ,UAAU,GAAC,IAAI,CAoB3B;IAGD,kCAOC;IAED,0BAOC;IAED,uCAsBC;IAED,4CASC;IAED,sBAmCC;IAED;;;;MAaC;IAKD,8BA4BC;IAED;;;OAGG;IACH,WAFa,kBAAkB,CAI9B;IAID,qNAWC;IAGD,uCAkBC;IAGD;;;OAGG;IACH,8BAHW,MAAM,GACJ,MAAM,EAAE,CASpB;CACF;6CA5pBS,cAAc;mCAAd,cAAc;kCAAd,cAAc;uCAAd,cAAc;oCAAd,cAAc;+BAAd,cAAc;wBAfA,yBAAyB;kCAevC,cAAc;gCAAd,cAAc;wCAAd,cAAc;4BAAd,cAAc"}
1
+ {"version":3,"file":"Document.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Document.svelte.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;GAOG;AACH,uCAJ0C,CAAC,SAA7B,MAAM,CAAC,MAAM,EAAE,UAAU,CAAE,UAC9B,CAAC,GACC,CAAC,CAIb;AAED;;;;GAIG;AACH,wCAHW,MAAM,GACJ,IAAI,IAAI,aAAa,CAQjC;AAED;;;;GAIG;AACH,2DAHW,YAAY,GAAG,iBAAiB,GAC9B,MAAM,GAAG,IAAI,CASzB;AAED;;;;GAIG;AACH,0DAHW,cAAc,QAexB;AAuGD;IAgGE;;;;;;OAMG;IACH,oBANW,cAAc,kBACd,kBAAkB,0BAE1B;QAA4B,SAAS,GAA7B,SAAS;QACK,MAAM,GAApB,GAAG;KACb,EAqBA;IAxHD,YAAkB;IAClB,iBAAuB;IACvB,WAAiB;IACjB,eAAqB;IACrB,sBAA2B;IAG3B,kBAA6C;IAC7C,kBAAkE;IAGnE,mBAAmD;IACnD,iBAA+C;IAC/C,gCAA6E;IAU5E;;;;OAIG;IACH,qBAHW,SAAS,GAAG,SAAS,EAQ/B;IAlBD;;;OAGG;IACH,iBAFa,SAAS,GAAG,SAAS,CAIjC;IAcD;;;;;;OAMG;IACH,4BAiDC;IAaC,uBAAoB;IAkBtB,mBAMC;IAED,sCAKA;IAGD,yBAkBC;IAID,uBAoBC;IAGA,yBAWC;IAED;;;;OAIG;IACH,oBAHW,GAAG,QAKb;IAED;;;;OAIG;IACH,UAFa,WAAW,CASvB;IAED;;;;OAIG;IACH,mBAFW,WAAW,QAkBrB;IAED,aAWC;IAED,aAaC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,UAlBW,YAAY,GAAC,MAAM,GACjB,GAAG,CAoFf;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,cAHW,YAAY,GACV;QAAC,IAAI,EAAE,UAAU,GAAC,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAC,CAuBzD;IAED;;;;;OAKG;IACH,WAHW,GAAG,GACD,QAAQ,CAIpB;IAED;;;;;;OAMG;IACH,mCAHW,MAAM,GACJ,UAAU,GAAC,IAAI,CAqB3B;IAGD,kCAOC;IAED,0BAOC;IAED,sBAmCC;IAED;;;;MAaC;IAKD,8BAgCC;IAED;;;OAGG;IACH,WAFa,kBAAkB,CAI9B;IAID,mNAWC;IAGD,uCAkBC;IAGD;;;OAGG;IACH,8BAHW,MAAM,GACJ,MAAM,EAAE,CASpB;;CACF;gCAxwBS,cAAc;mCAAd,cAAc;kCAAd,cAAc;uCAAd,cAAc;oCAAd,cAAc;+BAAd,cAAc;wBAnBA,yBAAyB;kCAmBvC,cAAc;8BAAd,cAAc;gCAAd,cAAc;wCAAd,cAAc;4BAAd,cAAc"}