@pod-os/elements 0.30.2-rc.ca6f577.0 → 0.31.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 (53) hide show
  1. package/dist/cjs/elements.cjs.js +1 -1
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/pos-document.cjs.entry.js +9 -6
  4. package/dist/cjs/pos-document.cjs.entry.js.map +1 -1
  5. package/dist/cjs/pos-markdown-document.cjs.entry.js +13481 -14042
  6. package/dist/cjs/pos-markdown-document.cjs.entry.js.map +1 -1
  7. package/dist/collection/components/pos-document/pos-document.js +10 -7
  8. package/dist/collection/components/pos-document/pos-document.js.map +1 -1
  9. package/dist/collection/components/pos-markdown-document/pos-markdown-document.css +17 -0
  10. package/dist/collection/components/pos-markdown-document/pos-markdown-document.js +33 -25
  11. package/dist/collection/components/pos-markdown-document/pos-markdown-document.js.map +1 -1
  12. package/dist/collection/components/pos-markdown-document/rich-editor/PosImageNode.js +25 -21
  13. package/dist/collection/components/pos-markdown-document/rich-editor/PosImageNode.js.map +1 -1
  14. package/dist/collection/components/pos-markdown-document/rich-editor/PosRichLinkMark.js +20 -16
  15. package/dist/collection/components/pos-markdown-document/rich-editor/PosRichLinkMark.js.map +1 -1
  16. package/dist/collection/components/pos-markdown-document/rich-editor/RichEditor.js +10 -24
  17. package/dist/collection/components/pos-markdown-document/rich-editor/RichEditor.js.map +1 -1
  18. package/dist/components/pos-document2.js +10 -7
  19. package/dist/components/pos-document2.js.map +1 -1
  20. package/dist/components/pos-markdown-document2.js +13483 -14044
  21. package/dist/components/pos-markdown-document2.js.map +1 -1
  22. package/dist/elements/elements.esm.js +1 -1
  23. package/dist/elements/elements.esm.js.map +1 -1
  24. package/dist/elements/p-08f92489.entry.js +2 -0
  25. package/dist/elements/p-08f92489.entry.js.map +1 -0
  26. package/dist/elements/p-4f8297e8.entry.js +2 -0
  27. package/dist/elements/p-4f8297e8.entry.js.map +1 -0
  28. package/dist/esm/elements.js +1 -1
  29. package/dist/esm/loader.js +1 -1
  30. package/dist/esm/pos-document.entry.js +9 -6
  31. package/dist/esm/pos-document.entry.js.map +1 -1
  32. package/dist/esm/pos-markdown-document.entry.js +13481 -14042
  33. package/dist/esm/pos-markdown-document.entry.js.map +1 -1
  34. package/dist/types/components/pos-document/pos-document.d.ts +1 -1
  35. package/dist/types/components/pos-markdown-document/pos-markdown-document.d.ts +5 -5
  36. package/dist/types/components/pos-markdown-document/rich-editor/PosImageNode.d.ts +2 -0
  37. package/dist/types/components/pos-markdown-document/rich-editor/PosRichLinkMark.d.ts +2 -0
  38. package/dist/types/components/pos-markdown-document/rich-editor/RichEditor.d.ts +1 -9
  39. package/dist/types/components.d.ts +4 -4
  40. package/package.json +9 -11
  41. package/dist/collection/components/pos-markdown-document/html2markdown.js +0 -10
  42. package/dist/collection/components/pos-markdown-document/html2markdown.js.map +0 -1
  43. package/dist/collection/components/pos-markdown-document/markdown2html.js +0 -5
  44. package/dist/collection/components/pos-markdown-document/markdown2html.js.map +0 -1
  45. package/dist/collection/components/pos-markdown-document/sanitize.js +0 -10
  46. package/dist/collection/components/pos-markdown-document/sanitize.js.map +0 -1
  47. package/dist/elements/p-581ed3ee.entry.js +0 -3
  48. package/dist/elements/p-581ed3ee.entry.js.map +0 -1
  49. package/dist/elements/p-ff3f95dc.entry.js +0 -2
  50. package/dist/elements/p-ff3f95dc.entry.js.map +0 -1
  51. package/dist/types/components/pos-markdown-document/html2markdown.d.ts +0 -1
  52. package/dist/types/components/pos-markdown-document/markdown2html.d.ts +0 -1
  53. package/dist/types/components/pos-markdown-document/sanitize.d.ts +0 -4
@@ -3,7 +3,7 @@ import session from "../../store/session";
3
3
  import { BrokenFile } from "../broken-file/BrokenFile";
4
4
  export class PosDocument {
5
5
  constructor() {
6
- this.savingFailed = false;
6
+ this.saveStatus = 'idle';
7
7
  this.loading = true;
8
8
  this.isEditable = false;
9
9
  this.setOs = async (os) => {
@@ -17,16 +17,19 @@ export class PosDocument {
17
17
  async handleDocumentModified(event) {
18
18
  const { file, newContent } = event.detail;
19
19
  try {
20
- this.savingFailed = false;
20
+ this.saveStatus = 'saving';
21
21
  const response = await this.os.files().putFile(file, newContent);
22
- if (!response.ok) {
23
- this.savingFailed = true;
22
+ if (response.ok) {
23
+ this.saveStatus = 'idle';
24
+ }
25
+ else {
26
+ this.saveStatus = 'failed';
24
27
  const error = new Error(`Failed to save file: ${response.status} ${response.statusText}`);
25
28
  this.errorEmitter.emit(error);
26
29
  }
27
30
  }
28
31
  catch (error) {
29
- this.savingFailed = true;
32
+ this.saveStatus = 'failed';
30
33
  this.errorEmitter.emit(error);
31
34
  }
32
35
  }
@@ -63,7 +66,7 @@ export class PosDocument {
63
66
  return h(BrokenFile, { file: this.brokenFile });
64
67
  }
65
68
  if (this.file.blob().type === 'text/markdown') {
66
- return (h("pos-markdown-document", { editable: this.isEditable, savingFailed: this.savingFailed, file: this.file }));
69
+ return (h("pos-markdown-document", { editable: this.isEditable, saveStatus: this.saveStatus, file: this.file }));
67
70
  }
68
71
  else {
69
72
  return h("iframe", { src: URL.createObjectURL(this.file.blob()) });
@@ -129,7 +132,7 @@ export class PosDocument {
129
132
  "file": {},
130
133
  "brokenFile": {},
131
134
  "error": {},
132
- "savingFailed": {},
135
+ "saveStatus": {},
133
136
  "loading": {},
134
137
  "isEditable": {}
135
138
  };
@@ -1 +1 @@
1
- {"version":3,"file":"pos-document.js","sourceRoot":"","sources":["../../../../src/components/pos-document/pos-document.tsx"],"names":[],"mappings":"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","sourcesContent":["import { PodOS, BrokenFile as BrokenFileData, SolidFile } from '@pod-os/core';\nimport { Component, Event, EventEmitter, h, Listen, Prop, State, Watch } from '@stencil/core';\nimport session from '../../store/session';\nimport { BrokenFile } from '../broken-file/BrokenFile';\n\n@Component({\n tag: 'pos-document',\n styleUrl: 'pos-document.css',\n shadow: true,\n})\nexport class PosDocument {\n @Prop() src: string;\n\n @Prop() alt: string;\n\n @State() os: PodOS;\n\n @State()\n private file: SolidFile;\n\n @State()\n private brokenFile: BrokenFileData;\n\n @State()\n private error: Error;\n\n @State()\n private savingFailed = false;\n\n @State()\n private loading: boolean = true;\n\n @State()\n private isEditable: boolean = false;\n\n @Event({ eventName: 'pod-os:init' }) initializeOsEmitter: EventEmitter;\n\n /**\n * Indicates that the resource given in `src` property has been loaded.\n */\n @Event({ eventName: 'pod-os:resource-loaded' }) resourceLoadedEmitter: EventEmitter<string>;\n\n /**\n * Emitted when an error occurs during file operations.\n */\n @Event({ eventName: 'pod-os:error' }) errorEmitter: EventEmitter<Error>;\n\n componentWillLoad() {\n session.onChange('isLoggedIn', () => this.fetchBlob());\n this.initializeOsEmitter.emit(this.setOs);\n }\n\n setOs = async (os: PodOS) => {\n this.os = os;\n };\n\n @Listen('pod-os:document-modified')\n async handleDocumentModified(event: CustomEvent) {\n const { file, newContent } = event.detail;\n try {\n this.savingFailed = false;\n const response = await this.os.files().putFile(file, newContent);\n if (!response.ok) {\n this.savingFailed = true;\n const error = new Error(`Failed to save file: ${response.status} ${response.statusText}`);\n this.errorEmitter.emit(error);\n }\n } catch (error) {\n this.savingFailed = true;\n this.errorEmitter.emit(error);\n }\n }\n\n @Watch('os')\n @Watch('src')\n async fetchBlob() {\n try {\n this.loading = true;\n const file = await this.os.files().fetchFile(this.src);\n const thing = this.os.store.get(this.src);\n this.isEditable = thing?.editable;\n this.resourceLoadedEmitter.emit(this.src);\n if (file.blob()) {\n this.file = file;\n this.error = null;\n } else {\n this.brokenFile = file as BrokenFileData;\n }\n } catch (err) {\n this.error = err;\n } finally {\n this.loading = false;\n }\n }\n\n render() {\n if (this.loading) {\n return <ion-skeleton-text animated={true}></ion-skeleton-text>;\n }\n if (this.error) {\n return <div class=\"error\">{this.error.message}</div>;\n }\n if (this.brokenFile) {\n return <BrokenFile file={this.brokenFile} />;\n }\n if (this.file.blob().type === 'text/markdown') {\n return (\n <pos-markdown-document\n editable={this.isEditable}\n savingFailed={this.savingFailed}\n file={this.file}\n ></pos-markdown-document>\n );\n } else {\n return <iframe src={URL.createObjectURL(this.file.blob())}></iframe>;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"pos-document.js","sourceRoot":"","sources":["../../../../src/components/pos-document/pos-document.tsx"],"names":[],"mappings":"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","sourcesContent":["import { PodOS, BrokenFile as BrokenFileData, SolidFile } from '@pod-os/core';\nimport { Component, Event, EventEmitter, h, Listen, Prop, State, Watch } from '@stencil/core';\nimport session from '../../store/session';\nimport { BrokenFile } from '../broken-file/BrokenFile';\n\n@Component({\n tag: 'pos-document',\n styleUrl: 'pos-document.css',\n shadow: true,\n})\nexport class PosDocument {\n @Prop() src: string;\n\n @Prop() alt: string;\n\n @State() os: PodOS;\n\n @State()\n private file: SolidFile;\n\n @State()\n private brokenFile: BrokenFileData;\n\n @State()\n private error: Error;\n\n @State()\n private saveStatus: 'idle' | 'saving' | 'failed' = 'idle';\n\n @State()\n private loading: boolean = true;\n\n @State()\n private isEditable: boolean = false;\n\n @Event({ eventName: 'pod-os:init' }) initializeOsEmitter: EventEmitter;\n\n /**\n * Indicates that the resource given in `src` property has been loaded.\n */\n @Event({ eventName: 'pod-os:resource-loaded' }) resourceLoadedEmitter: EventEmitter<string>;\n\n /**\n * Emitted when an error occurs during file operations.\n */\n @Event({ eventName: 'pod-os:error' }) errorEmitter: EventEmitter<Error>;\n\n componentWillLoad() {\n session.onChange('isLoggedIn', () => this.fetchBlob());\n this.initializeOsEmitter.emit(this.setOs);\n }\n\n setOs = async (os: PodOS) => {\n this.os = os;\n };\n\n @Listen('pod-os:document-modified')\n async handleDocumentModified(event: CustomEvent) {\n const { file, newContent } = event.detail;\n try {\n this.saveStatus = 'saving';\n const response = await this.os.files().putFile(file, newContent);\n if (response.ok) {\n this.saveStatus = 'idle';\n } else {\n this.saveStatus = 'failed';\n const error = new Error(`Failed to save file: ${response.status} ${response.statusText}`);\n this.errorEmitter.emit(error);\n }\n } catch (error) {\n this.saveStatus = 'failed';\n this.errorEmitter.emit(error);\n }\n }\n\n @Watch('os')\n @Watch('src')\n async fetchBlob() {\n try {\n this.loading = true;\n const file = await this.os.files().fetchFile(this.src);\n const thing = this.os.store.get(this.src);\n this.isEditable = thing?.editable;\n this.resourceLoadedEmitter.emit(this.src);\n if (file.blob()) {\n this.file = file;\n this.error = null;\n } else {\n this.brokenFile = file as BrokenFileData;\n }\n } catch (err) {\n this.error = err;\n } finally {\n this.loading = false;\n }\n }\n\n render() {\n if (this.loading) {\n return <ion-skeleton-text animated={true}></ion-skeleton-text>;\n }\n if (this.error) {\n return <div class=\"error\">{this.error.message}</div>;\n }\n if (this.brokenFile) {\n return <BrokenFile file={this.brokenFile} />;\n }\n if (this.file.blob().type === 'text/markdown') {\n return (\n <pos-markdown-document\n editable={this.isEditable}\n saveStatus={this.saveStatus}\n file={this.file}\n ></pos-markdown-document>\n );\n } else {\n return <iframe src={URL.createObjectURL(this.file.blob())}></iframe>;\n }\n }\n}\n"]}
@@ -67,6 +67,10 @@
67
67
  &.error {
68
68
  animation: error-flash 2s ease infinite;
69
69
  }
70
+
71
+ &.saving {
72
+ animation: saving-flash 2s ease infinite;
73
+ }
70
74
  }
71
75
  }
72
76
 
@@ -133,3 +137,16 @@
133
137
  opacity: 0;
134
138
  }
135
139
  }
140
+
141
+ @keyframes saving-flash {
142
+ 0% {
143
+ opacity: 0;
144
+ }
145
+ 50% {
146
+ opacity: 1;
147
+ color: var(--pos-primary-color);
148
+ }
149
+ 100% {
150
+ opacity: 0;
151
+ }
152
+ }
@@ -1,16 +1,13 @@
1
1
  import { h } from "@stencil/core";
2
- import { sanitize } from "./sanitize";
3
2
  import { RichEditor } from "./rich-editor";
4
3
  import "./shoelace";
5
4
  import { map, Subject, takeUntil, tap } from "rxjs";
6
- import { html2markdown } from "./html2markdown";
7
- import { markdown2html } from "./markdown2html";
8
5
  export class PosMarkdownDocument {
9
6
  constructor() {
10
7
  /**
11
- * Whether saving the latest changes failed
8
+ * Current save status
12
9
  */
13
- this.savingFailed = false;
10
+ this.saveStatus = 'idle';
14
11
  /**
15
12
  * Whether the current user has the permission to edit the file
16
13
  */
@@ -20,18 +17,16 @@ export class PosMarkdownDocument {
20
17
  this.disconnected$ = new Subject();
21
18
  }
22
19
  async componentWillLoad() {
23
- const markdown = await this.file.blob().text();
24
- const html = await markdown2html(markdown);
25
- this.sanitizedHtml = sanitize(html);
20
+ this.markdown = await this.file.blob().text();
26
21
  }
27
22
  componentDidLoad() {
28
- this.editor = new RichEditor(this.editorEl, this.sanitizedHtml, this.file.url);
23
+ this.editor = new RichEditor(this.editorEl, this.markdown, this.file.url);
29
24
  this.editor.onUpdate(() => {
30
- this.isModified = this.editor.isModified();
25
+ this.isModified = true;
31
26
  });
32
27
  this.editor
33
28
  .observeChanges()
34
- .pipe(takeUntil(this.disconnected$), map(changes => html2markdown(changes.content)), tap(markdown => {
29
+ .pipe(takeUntil(this.disconnected$), map(changes => changes.content), tap(markdown => {
35
30
  this.isModified = false;
36
31
  this.documentModified.emit({
37
32
  file: this.file,
@@ -47,27 +42,30 @@ export class PosMarkdownDocument {
47
42
  /**
48
43
  * Switch to editing mode
49
44
  */
50
- startEditing() {
45
+ async startEditing() {
51
46
  this.editor.startEditing();
52
47
  this.isEditing = true;
53
48
  }
54
49
  /**
55
50
  * Switch to view mode
56
51
  */
57
- stopEditing() {
52
+ async stopEditing() {
58
53
  this.editor.stopEditing();
59
54
  this.isEditing = false;
60
55
  }
61
56
  render() {
62
- return (h("article", { key: '21cbe982b1ead2ba403706407e05d97903e0073b' }, this.editable ? (h("header", null, this.isEditing ? this.getStatus() : null, this.isEditing ? (h("button", { onClick: () => this.stopEditing() }, h("sl-icon", { name: "eye" }), "View")) : (h("button", { onClick: () => this.startEditing() }, h("sl-icon", { name: "pencil-square" }), "Edit")))) : null, h("div", { key: '22f18aeef51e66cee8e7300fd82def756d8ae522', class: "content", ref: el => (this.editorEl = el) })));
57
+ return (h("article", { key: '99e920a07dfbde44c65415fac345ce183b4a6be3' }, this.editable ? (h("header", null, this.isEditing ? this.getStatus() : null, this.isEditing ? (h("button", { onClick: () => this.stopEditing() }, h("sl-icon", { name: "eye" }), "View")) : (h("button", { onClick: () => this.startEditing() }, h("sl-icon", { name: "pencil-square" }), "Edit")))) : null, h("div", { key: '8407b452e5a17be4e1db7a61621787ddc76bd279', class: "content", ref: el => (this.editorEl = el) })));
63
58
  }
64
59
  getStatus() {
65
60
  if (this.isModified) {
66
61
  return h(Status, { status: "pending", message: "pending changes", icon: "clock-history" });
67
62
  }
68
- if (this.savingFailed) {
63
+ if (this.saveStatus === 'failed') {
69
64
  return h(Status, { status: "error", message: "saving failed", icon: "x-octagon" });
70
65
  }
66
+ if (this.saveStatus === 'saving') {
67
+ return h(Status, { status: "saving", message: "saving changes", icon: "cloud-upload" });
68
+ }
71
69
  return h(Status, { status: "success", message: "all saved", icon: "check2-circle" });
72
70
  }
73
71
  static get is() { return "pos-markdown-document"; }
@@ -107,25 +105,25 @@ export class PosMarkdownDocument {
107
105
  "getter": false,
108
106
  "setter": false
109
107
  },
110
- "savingFailed": {
111
- "type": "boolean",
108
+ "saveStatus": {
109
+ "type": "string",
112
110
  "mutable": false,
113
111
  "complexType": {
114
- "original": "boolean",
115
- "resolved": "boolean",
112
+ "original": "'idle' | 'saving' | 'failed'",
113
+ "resolved": "\"failed\" | \"idle\" | \"saving\"",
116
114
  "references": {}
117
115
  },
118
116
  "required": false,
119
117
  "optional": false,
120
118
  "docs": {
121
119
  "tags": [],
122
- "text": "Whether saving the latest changes failed"
120
+ "text": "Current save status"
123
121
  },
124
122
  "getter": false,
125
123
  "setter": false,
126
- "attribute": "saving-failed",
124
+ "attribute": "save-status",
127
125
  "reflect": false,
128
- "defaultValue": "false"
126
+ "defaultValue": "'idle'"
129
127
  },
130
128
  "editable": {
131
129
  "type": "boolean",
@@ -151,7 +149,7 @@ export class PosMarkdownDocument {
151
149
  }
152
150
  static get states() {
153
151
  return {
154
- "sanitizedHtml": {},
152
+ "markdown": {},
155
153
  "isModified": {},
156
154
  "isEditing": {}
157
155
  };
@@ -185,7 +183,12 @@ export class PosMarkdownDocument {
185
183
  "complexType": {
186
184
  "signature": "() => Promise<void>",
187
185
  "parameters": [],
188
- "references": {},
186
+ "references": {
187
+ "Promise": {
188
+ "location": "global",
189
+ "id": "global::Promise"
190
+ }
191
+ },
189
192
  "return": "Promise<void>"
190
193
  },
191
194
  "docs": {
@@ -197,7 +200,12 @@ export class PosMarkdownDocument {
197
200
  "complexType": {
198
201
  "signature": "() => Promise<void>",
199
202
  "parameters": [],
200
- "references": {},
203
+ "references": {
204
+ "Promise": {
205
+ "location": "global",
206
+ "id": "global::Promise"
207
+ }
208
+ },
201
209
  "return": "Promise<void>"
202
210
  },
203
211
  "docs": {
@@ -1 +1 @@
1
- {"version":3,"file":"pos-markdown-document.js","sourceRoot":"","sources":["../../../../src/components/pos-markdown-document/pos-markdown-document.tsx"],"names":[],"mappings":"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","sourcesContent":["import { SolidFile } from '@pod-os/core';\nimport { Component, h, Method, Prop, State, Event, EventEmitter } from '@stencil/core';\n\nimport { sanitize, SanitizedHtml } from './sanitize';\nimport { RichEditor } from './rich-editor';\n\nimport './shoelace';\nimport { map, Subject, takeUntil, tap } from 'rxjs';\nimport { html2markdown } from './html2markdown';\nimport { markdown2html } from './markdown2html';\n\ninterface ModifiedFile {\n file: SolidFile;\n newContent: string;\n}\n\n@Component({\n tag: 'pos-markdown-document',\n styleUrls: ['pos-markdown-document.css', '../../apps/styles/article-card.css'],\n shadow: true,\n})\nexport class PosMarkdownDocument {\n /**\n * The file to show / edit\n */\n @Prop()\n file: SolidFile;\n\n /**\n * Whether saving the latest changes failed\n */\n @Prop()\n savingFailed: boolean = false;\n\n /**\n * Whether the current user has the permission to edit the file\n */\n @Prop()\n editable: boolean = false;\n\n @State()\n private sanitizedHtml: SanitizedHtml;\n\n private editorEl: HTMLElement;\n\n @State()\n private isModified: boolean = false;\n\n private editor: RichEditor;\n\n @State()\n private isEditing: boolean = false;\n\n /**\n * Event emitted when the document has been modified\n */\n @Event({ eventName: 'pod-os:document-modified' })\n documentModified: EventEmitter<ModifiedFile>;\n\n private readonly disconnected$ = new Subject<void>();\n\n async componentWillLoad() {\n const markdown = await this.file.blob().text();\n const html = await markdown2html(markdown);\n this.sanitizedHtml = sanitize(html);\n }\n\n componentDidLoad() {\n this.editor = new RichEditor(this.editorEl, this.sanitizedHtml, this.file.url);\n this.editor.onUpdate(() => {\n this.isModified = this.editor.isModified();\n });\n this.editor\n .observeChanges()\n .pipe(\n takeUntil(this.disconnected$),\n map(changes => html2markdown(changes.content)),\n tap(markdown => {\n this.isModified = false;\n this.documentModified.emit({\n file: this.file,\n newContent: markdown,\n });\n }),\n )\n .subscribe();\n }\n\n disconnectedCallback() {\n this.disconnected$.next();\n this.disconnected$.unsubscribe();\n }\n\n /**\n * Switch to editing mode\n */\n @Method()\n startEditing() {\n this.editor.startEditing();\n this.isEditing = true;\n }\n\n /**\n * Switch to view mode\n */\n @Method()\n stopEditing() {\n this.editor.stopEditing();\n this.isEditing = false;\n }\n\n render() {\n return (\n <article>\n {this.editable ? (\n <header>\n {this.isEditing ? this.getStatus() : null}\n {this.isEditing ? (\n <button onClick={() => this.stopEditing()}>\n <sl-icon name=\"eye\"></sl-icon>\n View\n </button>\n ) : (\n <button onClick={() => this.startEditing()}>\n <sl-icon name=\"pencil-square\"></sl-icon>\n Edit\n </button>\n )}\n </header>\n ) : null}\n <div class=\"content\" ref={el => (this.editorEl = el)}></div>\n </article>\n );\n }\n\n private getStatus() {\n if (this.isModified) {\n return <Status status=\"pending\" message=\"pending changes\" icon=\"clock-history\"></Status>;\n }\n if (this.savingFailed) {\n return <Status status=\"error\" message=\"saving failed\" icon=\"x-octagon\"></Status>;\n }\n return <Status status=\"success\" message=\"all saved\" icon=\"check2-circle\"></Status>;\n }\n}\n\nfunction Status({ status, icon, message }) {\n return (\n <span\n class={{\n status: true,\n [status]: true,\n }}\n role=\"status\"\n aria-live=\"polite\"\n aria-labelledby=\"status-message\"\n >\n <sl-icon name={icon} aria-hidden=\"true\"></sl-icon>\n <span id=\"status-message\">{message}</span>\n </span>\n );\n}\n"]}
1
+ {"version":3,"file":"pos-markdown-document.js","sourceRoot":"","sources":["../../../../src/components/pos-markdown-document/pos-markdown-document.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAgB,MAAM,eAAe,CAAC;AAEvF,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,YAAY,CAAC;AACpB,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAYpD,MAAM,OAAO,mBAAmB;IALhC;QAYE;;WAEG;QAEH,eAAU,GAAiC,MAAM,CAAC;QAElD;;WAEG;QAEH,aAAQ,GAAY,KAAK,CAAC;QAQlB,eAAU,GAAY,KAAK,CAAC;QAK5B,cAAS,GAAY,KAAK,CAAC;QAQlB,kBAAa,GAAG,IAAI,OAAO,EAAQ,CAAC;KAsFtD;IApFC,KAAK,CAAC,iBAAiB;QACrB,IAAI,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IAED,gBAAgB;QACd,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE;YACxB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM;aACR,cAAc,EAAE;aAChB,IAAI,CACH,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,EAC7B,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAC/B,GAAG,CAAC,QAAQ,CAAC,EAAE;YACb,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;YACxB,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;gBACzB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,UAAU,EAAE,QAAQ;aACrB,CAAC,CAAC;QACL,CAAC,CAAC,CACH;aACA,SAAS,EAAE,CAAC;IACjB,CAAC;IAED,oBAAoB;QAClB,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;QAC1B,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC;IAED;;OAEG;IAEH,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAED;;OAEG;IAEH,KAAK,CAAC,WAAW;QACf,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,MAAM;QACJ,OAAO,CACL;YACG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CACf;gBACG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI;gBACxC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAChB,cAAQ,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE;oBACvC,eAAS,IAAI,EAAC,KAAK,GAAW;2BAEvB,CACV,CAAC,CAAC,CAAC,CACF,cAAQ,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE;oBACxC,eAAS,IAAI,EAAC,eAAe,GAAW;2BAEjC,CACV,CACM,CACV,CAAC,CAAC,CAAC,IAAI;YACR,4DAAK,KAAK,EAAC,SAAS,EAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,GAAQ,CACpD,CACX,CAAC;IACJ,CAAC;IAEO,SAAS;QACf,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,OAAO,EAAC,MAAM,IAAC,MAAM,EAAC,SAAS,EAAC,OAAO,EAAC,iBAAiB,EAAC,IAAI,EAAC,eAAe,GAAU,CAAC;QAC3F,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,EAAC,MAAM,IAAC,MAAM,EAAC,OAAO,EAAC,OAAO,EAAC,eAAe,EAAC,IAAI,EAAC,WAAW,GAAU,CAAC;QACnF,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,EAAC,MAAM,IAAC,MAAM,EAAC,QAAQ,EAAC,OAAO,EAAC,gBAAgB,EAAC,IAAI,EAAC,cAAc,GAAU,CAAC;QACxF,CAAC;QACD,OAAO,EAAC,MAAM,IAAC,MAAM,EAAC,SAAS,EAAC,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,eAAe,GAAU,CAAC;IACrF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACF;AAED,SAAS,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;IACvC,OAAO,CACL,YACE,KAAK,EAAE;YACL,MAAM,EAAE,IAAI;YACZ,CAAC,MAAM,CAAC,EAAE,IAAI;SACf,EACD,IAAI,EAAC,QAAQ,eACH,QAAQ,qBACF,gBAAgB;QAEhC,eAAS,IAAI,EAAE,IAAI,iBAAc,MAAM,GAAW;QAClD,YAAM,EAAE,EAAC,gBAAgB,IAAE,OAAO,CAAQ,CACrC,CACR,CAAC;AACJ,CAAC","sourcesContent":["import { SolidFile } from '@pod-os/core';\nimport { Component, h, Method, Prop, State, Event, EventEmitter } from '@stencil/core';\n\nimport { RichEditor } from './rich-editor';\n\nimport './shoelace';\nimport { map, Subject, takeUntil, tap } from 'rxjs';\n\ninterface ModifiedFile {\n file: SolidFile;\n newContent: string;\n}\n\n@Component({\n tag: 'pos-markdown-document',\n styleUrls: ['pos-markdown-document.css', '../../apps/styles/article-card.css'],\n shadow: true,\n})\nexport class PosMarkdownDocument {\n /**\n * The file to show / edit\n */\n @Prop()\n file: SolidFile;\n\n /**\n * Current save status\n */\n @Prop()\n saveStatus: 'idle' | 'saving' | 'failed' = 'idle';\n\n /**\n * Whether the current user has the permission to edit the file\n */\n @Prop()\n editable: boolean = false;\n\n @State()\n private markdown: string;\n\n private editorEl: HTMLElement;\n\n @State()\n private isModified: boolean = false;\n\n private editor: RichEditor;\n\n @State()\n private isEditing: boolean = false;\n\n /**\n * Event emitted when the document has been modified\n */\n @Event({ eventName: 'pod-os:document-modified' })\n documentModified: EventEmitter<ModifiedFile>;\n\n private readonly disconnected$ = new Subject<void>();\n\n async componentWillLoad() {\n this.markdown = await this.file.blob().text();\n }\n\n componentDidLoad() {\n this.editor = new RichEditor(this.editorEl, this.markdown, this.file.url);\n this.editor.onUpdate(() => {\n this.isModified = true;\n });\n this.editor\n .observeChanges()\n .pipe(\n takeUntil(this.disconnected$),\n map(changes => changes.content),\n tap(markdown => {\n this.isModified = false;\n this.documentModified.emit({\n file: this.file,\n newContent: markdown,\n });\n }),\n )\n .subscribe();\n }\n\n disconnectedCallback() {\n this.disconnected$.next();\n this.disconnected$.unsubscribe();\n }\n\n /**\n * Switch to editing mode\n */\n @Method()\n async startEditing() {\n this.editor.startEditing();\n this.isEditing = true;\n }\n\n /**\n * Switch to view mode\n */\n @Method()\n async stopEditing() {\n this.editor.stopEditing();\n this.isEditing = false;\n }\n\n render() {\n return (\n <article>\n {this.editable ? (\n <header>\n {this.isEditing ? this.getStatus() : null}\n {this.isEditing ? (\n <button onClick={() => this.stopEditing()}>\n <sl-icon name=\"eye\"></sl-icon>\n View\n </button>\n ) : (\n <button onClick={() => this.startEditing()}>\n <sl-icon name=\"pencil-square\"></sl-icon>\n Edit\n </button>\n )}\n </header>\n ) : null}\n <div class=\"content\" ref={el => (this.editorEl = el)}></div>\n </article>\n );\n }\n\n private getStatus() {\n if (this.isModified) {\n return <Status status=\"pending\" message=\"pending changes\" icon=\"clock-history\"></Status>;\n }\n if (this.saveStatus === 'failed') {\n return <Status status=\"error\" message=\"saving failed\" icon=\"x-octagon\"></Status>;\n }\n if (this.saveStatus === 'saving') {\n return <Status status=\"saving\" message=\"saving changes\" icon=\"cloud-upload\"></Status>;\n }\n return <Status status=\"success\" message=\"all saved\" icon=\"check2-circle\"></Status>;\n }\n}\n\nfunction Status({ status, icon, message }) {\n return (\n <span\n class={{\n status: true,\n [status]: true,\n }}\n role=\"status\"\n aria-live=\"polite\"\n aria-labelledby=\"status-message\"\n >\n <sl-icon name={icon} aria-hidden=\"true\"></sl-icon>\n <span id=\"status-message\">{message}</span>\n </span>\n );\n}\n"]}
@@ -1,27 +1,31 @@
1
1
  import Image from "@tiptap/extension-image";
2
+ const allowedProtocols = new Set(['http:', 'https:']);
3
+ export const createNodeView = baseUrl => ({ HTMLAttributes }) => {
4
+ const container = document.createElement('pos-image');
5
+ const uri = new URL(HTMLAttributes.src, baseUrl);
6
+ if (allowedProtocols.has(uri.protocol)) {
7
+ container.setAttribute('src', uri.toString());
8
+ }
9
+ let attrsToKeep = ['alt', 'title'];
10
+ for (const attr of attrsToKeep) {
11
+ if (HTMLAttributes[attr]) {
12
+ container.setAttribute(attr, HTMLAttributes[attr]);
13
+ }
14
+ }
15
+ return {
16
+ dom: container,
17
+ /**
18
+ * ignoreMutation because:
19
+ * - `pos-image` handles its own internal DOM updates
20
+ * - We don't want the editor to interfere with the component's internal structure
21
+ * - The component content shouldn't trigger editor updates
22
+ */
23
+ ignoreMutation: () => true,
24
+ };
25
+ };
2
26
  export const PosImageNode = (baseUrl) => Image.extend({
3
27
  addNodeView() {
4
- return ({ HTMLAttributes }) => {
5
- const container = document.createElement('pos-image');
6
- const uri = new URL(HTMLAttributes.src, baseUrl);
7
- container.setAttribute('src', uri.toString());
8
- let attrsToKeep = ['alt', 'title'];
9
- for (const attr of attrsToKeep) {
10
- if (HTMLAttributes[attr]) {
11
- container.setAttribute(attr, HTMLAttributes[attr]);
12
- }
13
- }
14
- return {
15
- dom: container,
16
- /**
17
- * ignoreMutation because:
18
- * - `pos-image` handles its own internal DOM updates
19
- * - We don't want the editor to interfere with the component's internal structure
20
- * - The component content shouldn't trigger editor updates
21
- */
22
- ignoreMutation: () => true,
23
- };
24
- };
28
+ return createNodeView(baseUrl);
25
29
  },
26
30
  });
27
31
  //# sourceMappingURL=PosImageNode.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PosImageNode.js","sourceRoot":"","sources":["../../../../../src/components/pos-markdown-document/rich-editor/PosImageNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,yBAAyB,CAAC;AAE5C,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,EAAE,CAC9C,KAAK,CAAC,MAAM,CAAC;IACX,WAAW;QACT,OAAO,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE;YAC5B,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;YAEtD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACjD,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC9C,IAAI,WAAW,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACnC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;gBAC/B,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzB,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC;YAED,OAAO;gBACL,GAAG,EAAE,SAAS;gBACd;;;;;mBAKG;gBACH,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;aAC3B,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["import Image from '@tiptap/extension-image';\n\nexport const PosImageNode = (baseUrl: string) =>\n Image.extend({\n addNodeView() {\n return ({ HTMLAttributes }) => {\n const container = document.createElement('pos-image');\n\n const uri = new URL(HTMLAttributes.src, baseUrl);\n container.setAttribute('src', uri.toString());\n let attrsToKeep = ['alt', 'title'];\n for (const attr of attrsToKeep) {\n if (HTMLAttributes[attr]) {\n container.setAttribute(attr, HTMLAttributes[attr]);\n }\n }\n\n return {\n dom: container,\n /**\n * ignoreMutation because:\n * - `pos-image` handles its own internal DOM updates\n * - We don't want the editor to interfere with the component's internal structure\n * - The component content shouldn't trigger editor updates\n */\n ignoreMutation: () => true,\n };\n };\n },\n });\n"]}
1
+ {"version":3,"file":"PosImageNode.js","sourceRoot":"","sources":["../../../../../src/components/pos-markdown-document/rich-editor/PosImageNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,yBAAyB,CAAC;AAG5C,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEtD,MAAM,CAAC,MAAM,cAAc,GACzB,OAAO,CAAC,EAAE,CACV,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE;IACrB,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAEtD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACjD,IAAI,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,WAAW,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,OAAO;QACL,GAAG,EAAE,SAAS;QACd;;;;;WAKG;QACH,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;KAC3B,CAAC;AACJ,CAAC,CAAC;AAEJ,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,EAAE,CAC9C,KAAK,CAAC,MAAM,CAAC;IACX,WAAW;QACT,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACF,CAAC,CAAC","sourcesContent":["import Image from '@tiptap/extension-image';\nimport { NodeViewRenderer } from '@tiptap/core';\n\nconst allowedProtocols = new Set(['http:', 'https:']);\n\nexport const createNodeView: (baseUrl: string) => NodeViewRenderer =\n baseUrl =>\n ({ HTMLAttributes }) => {\n const container = document.createElement('pos-image');\n\n const uri = new URL(HTMLAttributes.src, baseUrl);\n if (allowedProtocols.has(uri.protocol)) {\n container.setAttribute('src', uri.toString());\n }\n let attrsToKeep = ['alt', 'title'];\n for (const attr of attrsToKeep) {\n if (HTMLAttributes[attr]) {\n container.setAttribute(attr, HTMLAttributes[attr]);\n }\n }\n\n return {\n dom: container,\n /**\n * ignoreMutation because:\n * - `pos-image` handles its own internal DOM updates\n * - We don't want the editor to interfere with the component's internal structure\n * - The component content shouldn't trigger editor updates\n */\n ignoreMutation: () => true,\n };\n };\n\nexport const PosImageNode = (baseUrl: string) =>\n Image.extend({\n addNodeView() {\n return createNodeView(baseUrl);\n },\n });\n"]}
@@ -1,22 +1,26 @@
1
1
  import Link from "@tiptap/extension-link";
2
+ const allowedProtocols = new Set(['http:', 'https:', 'mailto:', 'tel:']);
3
+ export const createMarkViewRenderer = baseUrl => ({ HTMLAttributes }) => {
4
+ const container = document.createElement('pos-rich-link');
5
+ const uri = new URL(HTMLAttributes.href, baseUrl);
6
+ if (allowedProtocols.has(uri.protocol)) {
7
+ container.setAttribute('uri', uri.toString());
8
+ }
9
+ return {
10
+ dom: container,
11
+ contentDOM: container,
12
+ /**
13
+ * ignoreMutation because:
14
+ * - `pos-rich-link` handles its own internal DOM updates
15
+ * - We don't want the editor to interfere with the component's internal structure
16
+ * - The component content shouldn't trigger editor updates
17
+ */
18
+ ignoreMutation: () => true,
19
+ };
20
+ };
2
21
  export const PosRichLinkMark = (baseUrl) => Link.extend({
3
22
  addMarkView() {
4
- return ({ HTMLAttributes }) => {
5
- const container = document.createElement('pos-rich-link');
6
- const uri = new URL(HTMLAttributes.href, baseUrl);
7
- container.setAttribute('uri', uri.toString());
8
- return {
9
- dom: container,
10
- contentDOM: container,
11
- /**
12
- * ignoreMutation because:
13
- * - `pos-rich-link` handles its own internal DOM updates
14
- * - We don't want the editor to interfere with the component's internal structure
15
- * - The component content shouldn't trigger editor updates
16
- */
17
- ignoreMutation: () => true,
18
- };
19
- };
23
+ return createMarkViewRenderer(baseUrl);
20
24
  },
21
25
  });
22
26
  //# sourceMappingURL=PosRichLinkMark.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PosRichLinkMark.js","sourceRoot":"","sources":["../../../../../src/components/pos-markdown-document/rich-editor/PosRichLinkMark.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,wBAAwB,CAAC;AAE1C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAe,EAAE,EAAE,CACjD,IAAI,CAAC,MAAM,CAAC;IACV,WAAW;QACT,OAAO,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE;YAC5B,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;YAC1D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAClD,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YAE9C,OAAO;gBACL,GAAG,EAAE,SAAS;gBACd,UAAU,EAAE,SAAS;gBACrB;;;;;mBAKG;gBACH,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;aAC3B,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["import Link from '@tiptap/extension-link';\n\nexport const PosRichLinkMark = (baseUrl: string) =>\n Link.extend({\n addMarkView() {\n return ({ HTMLAttributes }) => {\n const container = document.createElement('pos-rich-link');\n const uri = new URL(HTMLAttributes.href, baseUrl);\n container.setAttribute('uri', uri.toString());\n\n return {\n dom: container,\n contentDOM: container,\n /**\n * ignoreMutation because:\n * - `pos-rich-link` handles its own internal DOM updates\n * - We don't want the editor to interfere with the component's internal structure\n * - The component content shouldn't trigger editor updates\n */\n ignoreMutation: () => true,\n };\n };\n },\n });\n"]}
1
+ {"version":3,"file":"PosRichLinkMark.js","sourceRoot":"","sources":["../../../../../src/components/pos-markdown-document/rich-editor/PosRichLinkMark.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,wBAAwB,CAAC;AAG1C,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAEzE,MAAM,CAAC,MAAM,sBAAsB,GACjC,OAAO,CAAC,EAAE,CACV,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE;IACrB,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAClD,IAAI,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,OAAO;QACL,GAAG,EAAE,SAAS;QACd,UAAU,EAAE,SAAS;QACrB;;;;;WAKG;QACH,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;KAC3B,CAAC;AACJ,CAAC,CAAC;AAEJ,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAe,EAAE,EAAE,CACjD,IAAI,CAAC,MAAM,CAAC;IACV,WAAW;QACT,OAAO,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;CACF,CAAC,CAAC","sourcesContent":["import Link from '@tiptap/extension-link';\nimport { MarkViewRenderer } from '@tiptap/core';\n\nconst allowedProtocols = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\nexport const createMarkViewRenderer: (baseUrl: string) => MarkViewRenderer =\n baseUrl =>\n ({ HTMLAttributes }) => {\n const container = document.createElement('pos-rich-link');\n const uri = new URL(HTMLAttributes.href, baseUrl);\n if (allowedProtocols.has(uri.protocol)) {\n container.setAttribute('uri', uri.toString());\n }\n\n return {\n dom: container,\n contentDOM: container,\n /**\n * ignoreMutation because:\n * - `pos-rich-link` handles its own internal DOM updates\n * - We don't want the editor to interfere with the component's internal structure\n * - The component content shouldn't trigger editor updates\n */\n ignoreMutation: () => true,\n };\n };\n\nexport const PosRichLinkMark = (baseUrl: string) =>\n Link.extend({\n addMarkView() {\n return createMarkViewRenderer(baseUrl);\n },\n });\n"]}
@@ -1,8 +1,9 @@
1
1
  import { Editor } from "@tiptap/core";
2
+ import { Markdown } from "@tiptap/markdown";
2
3
  import StarterKit from "@tiptap/starter-kit";
3
4
  import { PosImageNode } from "./PosImageNode";
4
5
  import { PosRichLinkMark } from "./PosRichLinkMark";
5
- import { Subject, tap } from "rxjs";
6
+ import { Subject } from "rxjs";
6
7
  import { debounceTime } from "rxjs/operators";
7
8
  export class RichEditor {
8
9
  /**
@@ -11,26 +12,16 @@ export class RichEditor {
11
12
  * @param baseUrl Base URL for relative links and relative image src
12
13
  */
13
14
  constructor(target, content, baseUrl) {
14
- /**
15
- * Whether the editor has been modified since the latest changes have been observed
16
- * @private
17
- */
18
- this.modified = false;
19
- this.editingJustChanged = false;
20
15
  this.modifications = new Subject();
21
16
  this.editor = new Editor({
22
17
  element: target,
23
- extensions: [StarterKit.configure({ link: false }), PosImageNode(baseUrl), PosRichLinkMark(baseUrl)],
24
- content: content.value,
18
+ extensions: [Markdown, StarterKit.configure({ link: false }), PosImageNode(baseUrl), PosRichLinkMark(baseUrl)],
19
+ content: content,
20
+ contentType: 'markdown',
25
21
  editable: false,
26
22
  });
27
23
  this.editor.on('update', () => {
28
- if (this.editingJustChanged) {
29
- this.editingJustChanged = false;
30
- return;
31
- }
32
- this.modified = true;
33
- this.modifications.next({ content: this.editor.getHTML() });
24
+ this.modifications.next({ content: this.editor.getMarkdown() });
34
25
  });
35
26
  }
36
27
  onUpdate(callback) {
@@ -40,26 +31,21 @@ export class RichEditor {
40
31
  return this.editor.isEditable;
41
32
  }
42
33
  startEditing() {
43
- this.editingJustChanged = true;
44
- this.editor.setEditable(true);
34
+ this.editor.setEditable(true, false);
45
35
  this.editor.commands.focus();
46
36
  }
47
37
  stopEditing() {
48
- this.editingJustChanged = true;
49
- this.editor.setEditable(false);
50
- }
51
- isModified() {
52
- return this.modified;
38
+ this.editor.setEditable(false, false);
53
39
  }
54
40
  getContent() {
55
- return this.editor.getHTML();
41
+ return this.editor.getMarkdown();
56
42
  }
57
43
  /**
58
44
  * Provides an observable that communicates the latest editor content after changes have settled
59
45
  * @param debounce - time (in millisecond) that has to pass without further modifications, until the changes are communicated
60
46
  */
61
47
  observeChanges(debounce = 1000) {
62
- return this.modifications.pipe(debounceTime(debounce), tap(() => (this.modified = false)));
48
+ return this.modifications.pipe(debounceTime(debounce));
63
49
  }
64
50
  }
65
51
  //# sourceMappingURL=RichEditor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RichEditor.js","sourceRoot":"","sources":["../../../../../src/components/pos-markdown-document/rich-editor/RichEditor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,UAAU,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,OAAO,UAAU;IAYrB;;;;OAIG;IACH,YAAY,MAAmB,EAAE,OAAsB,EAAE,OAAe;QAdxE;;;WAGG;QACK,aAAQ,GAAG,KAAK,CAAC;QAEjB,uBAAkB,GAAG,KAAK,CAAC;QAClB,kBAAa,GAAG,IAAI,OAAO,EAAuB,CAAC;QAQlE,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC;YACvB,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;YACpG,OAAO,EAAE,OAAO,CAAC,KAAK;YACtB,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC5B,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBAC5B,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;gBAChC,OAAO;YACT,CAAC;YACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,QAAoB;QAC3B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;IAChC,CAAC;IAED,YAAY;QACV,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;IAED,WAAW;QACT,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,WAAmB,IAAI;QACpC,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAC5B,YAAY,CAAC,QAAQ,CAAC,EACtB,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,CACnC,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { Editor } from '@tiptap/core';\nimport StarterKit from '@tiptap/starter-kit';\nimport { PosImageNode } from './PosImageNode';\nimport { PosRichLinkMark } from './PosRichLinkMark';\nimport { SanitizedHtml } from '../sanitize';\nimport { Subject, tap } from 'rxjs';\nimport { debounceTime } from 'rxjs/operators';\n\nexport class RichEditor {\n private readonly editor: Editor;\n\n /**\n * Whether the editor has been modified since the latest changes have been observed\n * @private\n */\n private modified = false;\n\n private editingJustChanged = false;\n private readonly modifications = new Subject<{ content: string }>();\n\n /**\n * @param target The element to render to\n * @param content The content to show in the editor\n * @param baseUrl Base URL for relative links and relative image src\n */\n constructor(target: HTMLElement, content: SanitizedHtml, baseUrl: string) {\n this.editor = new Editor({\n element: target,\n extensions: [StarterKit.configure({ link: false }), PosImageNode(baseUrl), PosRichLinkMark(baseUrl)],\n content: content.value,\n editable: false,\n });\n this.editor.on('update', () => {\n if (this.editingJustChanged) {\n this.editingJustChanged = false;\n return;\n }\n this.modified = true;\n this.modifications.next({ content: this.editor.getHTML() });\n });\n }\n\n onUpdate(callback: () => void) {\n this.editor.on('update', callback);\n }\n\n isEditable() {\n return this.editor.isEditable;\n }\n\n startEditing() {\n this.editingJustChanged = true;\n this.editor.setEditable(true);\n this.editor.commands.focus();\n }\n\n stopEditing() {\n this.editingJustChanged = true;\n this.editor.setEditable(false);\n }\n\n isModified() {\n return this.modified;\n }\n\n getContent() {\n return this.editor.getHTML();\n }\n\n /**\n * Provides an observable that communicates the latest editor content after changes have settled\n * @param debounce - time (in millisecond) that has to pass without further modifications, until the changes are communicated\n */\n observeChanges(debounce: number = 1000) {\n return this.modifications.pipe(\n debounceTime(debounce),\n tap(() => (this.modified = false)),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"RichEditor.js","sourceRoot":"","sources":["../../../../../src/components/pos-markdown-document/rich-editor/RichEditor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,UAAU,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,OAAO,UAAU;IAKrB;;;;OAIG;IACH,YAAY,MAAmB,EAAE,OAAe,EAAE,OAAe;QAPhD,kBAAa,GAAG,IAAI,OAAO,EAAuB,CAAC;QAQlE,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC;YACvB,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;YAC9G,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,UAAU;YACvB,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC5B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,QAAoB;QAC3B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;IAChC,CAAC;IAED,YAAY;QACV,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;IAED,WAAW;QACT,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,WAAmB,IAAI;QACpC,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;IACzD,CAAC;CACF","sourcesContent":["import { Editor } from '@tiptap/core';\nimport { Markdown } from '@tiptap/markdown';\nimport StarterKit from '@tiptap/starter-kit';\nimport { PosImageNode } from './PosImageNode';\nimport { PosRichLinkMark } from './PosRichLinkMark';\nimport { Subject } from 'rxjs';\nimport { debounceTime } from 'rxjs/operators';\n\nexport class RichEditor {\n private readonly editor: Editor;\n\n private readonly modifications = new Subject<{ content: string }>();\n\n /**\n * @param target The element to render to\n * @param content The content to show in the editor\n * @param baseUrl Base URL for relative links and relative image src\n */\n constructor(target: HTMLElement, content: string, baseUrl: string) {\n this.editor = new Editor({\n element: target,\n extensions: [Markdown, StarterKit.configure({ link: false }), PosImageNode(baseUrl), PosRichLinkMark(baseUrl)],\n content: content,\n contentType: 'markdown',\n editable: false,\n });\n this.editor.on('update', () => {\n this.modifications.next({ content: this.editor.getMarkdown() });\n });\n }\n\n onUpdate(callback: () => void) {\n this.editor.on('update', callback);\n }\n\n isEditable() {\n return this.editor.isEditable;\n }\n\n startEditing() {\n this.editor.setEditable(true, false);\n this.editor.commands.focus();\n }\n\n stopEditing() {\n this.editor.setEditable(false, false);\n }\n\n getContent() {\n return this.editor.getMarkdown();\n }\n\n /**\n * Provides an observable that communicates the latest editor content after changes have settled\n * @param debounce - time (in millisecond) that has to pass without further modifications, until the changes are communicated\n */\n observeChanges(debounce: number = 1000) {\n return this.modifications.pipe(debounceTime(debounce));\n }\n}\n"]}
@@ -16,7 +16,7 @@ const PosDocument = /*@__PURE__*/ proxyCustomElement(class PosDocument extends H
16
16
  this.initializeOsEmitter = createEvent(this, "pod-os:init", 7);
17
17
  this.resourceLoadedEmitter = createEvent(this, "pod-os:resource-loaded", 7);
18
18
  this.errorEmitter = createEvent(this, "pod-os:error", 7);
19
- this.savingFailed = false;
19
+ this.saveStatus = 'idle';
20
20
  this.loading = true;
21
21
  this.isEditable = false;
22
22
  this.setOs = async (os) => {
@@ -30,16 +30,19 @@ const PosDocument = /*@__PURE__*/ proxyCustomElement(class PosDocument extends H
30
30
  async handleDocumentModified(event) {
31
31
  const { file, newContent } = event.detail;
32
32
  try {
33
- this.savingFailed = false;
33
+ this.saveStatus = 'saving';
34
34
  const response = await this.os.files().putFile(file, newContent);
35
- if (!response.ok) {
36
- this.savingFailed = true;
35
+ if (response.ok) {
36
+ this.saveStatus = 'idle';
37
+ }
38
+ else {
39
+ this.saveStatus = 'failed';
37
40
  const error = new Error(`Failed to save file: ${response.status} ${response.statusText}`);
38
41
  this.errorEmitter.emit(error);
39
42
  }
40
43
  }
41
44
  catch (error) {
42
- this.savingFailed = true;
45
+ this.saveStatus = 'failed';
43
46
  this.errorEmitter.emit(error);
44
47
  }
45
48
  }
@@ -76,7 +79,7 @@ const PosDocument = /*@__PURE__*/ proxyCustomElement(class PosDocument extends H
76
79
  return h(BrokenFile, { file: this.brokenFile });
77
80
  }
78
81
  if (this.file.blob().type === 'text/markdown') {
79
- return (h("pos-markdown-document", { editable: this.isEditable, savingFailed: this.savingFailed, file: this.file }));
82
+ return (h("pos-markdown-document", { editable: this.isEditable, saveStatus: this.saveStatus, file: this.file }));
80
83
  }
81
84
  else {
82
85
  return h("iframe", { src: URL.createObjectURL(this.file.blob()) });
@@ -94,7 +97,7 @@ const PosDocument = /*@__PURE__*/ proxyCustomElement(class PosDocument extends H
94
97
  "file": [32],
95
98
  "brokenFile": [32],
96
99
  "error": [32],
97
- "savingFailed": [32],
100
+ "saveStatus": [32],
98
101
  "loading": [32],
99
102
  "isEditable": [32]
100
103
  }, [[0, "pod-os:document-modified", "handleDocumentModified"]], {
@@ -1 +1 @@
1
- {"file":"pos-document2.js","mappings":"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","names":["session"],"sources":["src/components/pos-document/pos-document.css?tag=pos-document&encapsulation=shadow","src/components/pos-document/pos-document.tsx"],"sourcesContent":["iframe {\n background-color: var(--pos-background-color);\n width: 100%;\n height: 100vh;\n}\n\n/* consolidate with styles from pos-image */\n.error {\n display: flex;\n opacity: 0.8;\n background: repeating-linear-gradient(-45deg, rgba(150, 0, 0, 0.1), rgba(150, 0, 0, 0.1) 10px, #fff 5px, #fff 25px);\n flex-direction: column;\n border: 1px solid red;\n color: black;\n align-items: center;\n justify-content: center;\n word-break: break-all;\n padding: 1rem;\n box-sizing: border-box;\n}\n\n.error ion-icon {\n color: #282828;\n --ionicon-stroke-width: calc(var(--width) / 5);\n font-size: calc(var(--width) / 2);\n}\n\na {\n text-decoration: none;\n width: var(--width);\n height: var(--height);\n}\n\n.code {\n font-weight: bold;\n font-size: calc(var(--width) / 8);\n}\n\n.text {\n font-size: calc(var(--width) / 20);\n}\n","import { PodOS, BrokenFile as BrokenFileData, SolidFile } from '@pod-os/core';\nimport { Component, Event, EventEmitter, h, Listen, Prop, State, Watch } from '@stencil/core';\nimport session from '../../store/session';\nimport { BrokenFile } from '../broken-file/BrokenFile';\n\n@Component({\n tag: 'pos-document',\n styleUrl: 'pos-document.css',\n shadow: true,\n})\nexport class PosDocument {\n @Prop() src: string;\n\n @Prop() alt: string;\n\n @State() os: PodOS;\n\n @State()\n private file: SolidFile;\n\n @State()\n private brokenFile: BrokenFileData;\n\n @State()\n private error: Error;\n\n @State()\n private savingFailed = false;\n\n @State()\n private loading: boolean = true;\n\n @State()\n private isEditable: boolean = false;\n\n @Event({ eventName: 'pod-os:init' }) initializeOsEmitter: EventEmitter;\n\n /**\n * Indicates that the resource given in `src` property has been loaded.\n */\n @Event({ eventName: 'pod-os:resource-loaded' }) resourceLoadedEmitter: EventEmitter<string>;\n\n /**\n * Emitted when an error occurs during file operations.\n */\n @Event({ eventName: 'pod-os:error' }) errorEmitter: EventEmitter<Error>;\n\n componentWillLoad() {\n session.onChange('isLoggedIn', () => this.fetchBlob());\n this.initializeOsEmitter.emit(this.setOs);\n }\n\n setOs = async (os: PodOS) => {\n this.os = os;\n };\n\n @Listen('pod-os:document-modified')\n async handleDocumentModified(event: CustomEvent) {\n const { file, newContent } = event.detail;\n try {\n this.savingFailed = false;\n const response = await this.os.files().putFile(file, newContent);\n if (!response.ok) {\n this.savingFailed = true;\n const error = new Error(`Failed to save file: ${response.status} ${response.statusText}`);\n this.errorEmitter.emit(error);\n }\n } catch (error) {\n this.savingFailed = true;\n this.errorEmitter.emit(error);\n }\n }\n\n @Watch('os')\n @Watch('src')\n async fetchBlob() {\n try {\n this.loading = true;\n const file = await this.os.files().fetchFile(this.src);\n const thing = this.os.store.get(this.src);\n this.isEditable = thing?.editable;\n this.resourceLoadedEmitter.emit(this.src);\n if (file.blob()) {\n this.file = file;\n this.error = null;\n } else {\n this.brokenFile = file as BrokenFileData;\n }\n } catch (err) {\n this.error = err;\n } finally {\n this.loading = false;\n }\n }\n\n render() {\n if (this.loading) {\n return <ion-skeleton-text animated={true}></ion-skeleton-text>;\n }\n if (this.error) {\n return <div class=\"error\">{this.error.message}</div>;\n }\n if (this.brokenFile) {\n return <BrokenFile file={this.brokenFile} />;\n }\n if (this.file.blob().type === 'text/markdown') {\n return (\n <pos-markdown-document\n editable={this.isEditable}\n savingFailed={this.savingFailed}\n file={this.file}\n ></pos-markdown-document>\n );\n } else {\n return <iframe src={URL.createObjectURL(this.file.blob())}></iframe>;\n }\n }\n}\n"],"version":3}
1
+ {"file":"pos-document2.js","mappings":";;;;;;;AAAA,MAAM,cAAc,GAAG,soBAAsoB,CAAC;AAC9pB,0BAAe,cAAc;;MCShB,WAAW;IALxB;;;;;;;QAsBU,eAAU,GAAiC,MAAM,CAAC;QAGlD,YAAO,GAAY,IAAI,CAAC;QAGxB,eAAU,GAAY,KAAK,CAAC;QAmBpC,UAAK,GAAG,OAAO,EAAS;YACtB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;SACd,CAAC;KAiEH;IAxEC,iBAAiB;QACfA,KAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;KAC3C;IAOD,MAAM,sBAAsB,CAAC,KAAkB;QAC7C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;QAC1C,IAAI;YACF,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC;YAC3B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YACjE,IAAI,QAAQ,CAAC,EAAE,EAAE;gBACf,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;aAC1B;iBAAM;gBACL,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC;gBAC3B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,wBAAwB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;gBAC1F,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;aAC/B;SACF;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC;YAC3B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SAC/B;KACF;IAID,MAAM,SAAS;QACb,IAAI;YACF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1C,IAAI,CAAC,UAAU,GAAG,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,QAAQ,CAAC;YAClC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1C,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE;gBACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;gBACjB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;aACnB;iBAAM;gBACL,IAAI,CAAC,UAAU,GAAG,IAAsB,CAAC;aAC1C;SACF;QAAC,OAAO,GAAG,EAAE;YACZ,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;SAClB;gBAAS;YACR,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;SACtB;KACF;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,OAAO,EAAE;YAChB,OAAO,yBAAmB,QAAQ,EAAE,IAAI,GAAsB,CAAC;SAChE;QACD,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,OAAO,WAAK,KAAK,EAAC,OAAO,IAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAO,CAAC;SACtD;QACD,IAAI,IAAI,CAAC,UAAU,EAAE;YACnB,OAAO,EAAC,UAAU,IAAC,IAAI,EAAE,IAAI,CAAC,UAAU,GAAI,CAAC;SAC9C;QACD,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,eAAe,EAAE;YAC7C,QACE,6BACE,QAAQ,EAAE,IAAI,CAAC,UAAU,EACzB,UAAU,EAAE,IAAI,CAAC,UAAU,EAC3B,IAAI,EAAE,IAAI,CAAC,IAAI,GACQ,EACzB;SACH;aAAM;YACL,OAAO,cAAQ,GAAG,EAAE,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAW,CAAC;SACtE;KACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","names":["session"],"sources":["src/components/pos-document/pos-document.css?tag=pos-document&encapsulation=shadow","src/components/pos-document/pos-document.tsx"],"sourcesContent":["iframe {\n background-color: var(--pos-background-color);\n width: 100%;\n height: 100vh;\n}\n\n/* consolidate with styles from pos-image */\n.error {\n display: flex;\n opacity: 0.8;\n background: repeating-linear-gradient(-45deg, rgba(150, 0, 0, 0.1), rgba(150, 0, 0, 0.1) 10px, #fff 5px, #fff 25px);\n flex-direction: column;\n border: 1px solid red;\n color: black;\n align-items: center;\n justify-content: center;\n word-break: break-all;\n padding: 1rem;\n box-sizing: border-box;\n}\n\n.error ion-icon {\n color: #282828;\n --ionicon-stroke-width: calc(var(--width) / 5);\n font-size: calc(var(--width) / 2);\n}\n\na {\n text-decoration: none;\n width: var(--width);\n height: var(--height);\n}\n\n.code {\n font-weight: bold;\n font-size: calc(var(--width) / 8);\n}\n\n.text {\n font-size: calc(var(--width) / 20);\n}\n","import { PodOS, BrokenFile as BrokenFileData, SolidFile } from '@pod-os/core';\nimport { Component, Event, EventEmitter, h, Listen, Prop, State, Watch } from '@stencil/core';\nimport session from '../../store/session';\nimport { BrokenFile } from '../broken-file/BrokenFile';\n\n@Component({\n tag: 'pos-document',\n styleUrl: 'pos-document.css',\n shadow: true,\n})\nexport class PosDocument {\n @Prop() src: string;\n\n @Prop() alt: string;\n\n @State() os: PodOS;\n\n @State()\n private file: SolidFile;\n\n @State()\n private brokenFile: BrokenFileData;\n\n @State()\n private error: Error;\n\n @State()\n private saveStatus: 'idle' | 'saving' | 'failed' = 'idle';\n\n @State()\n private loading: boolean = true;\n\n @State()\n private isEditable: boolean = false;\n\n @Event({ eventName: 'pod-os:init' }) initializeOsEmitter: EventEmitter;\n\n /**\n * Indicates that the resource given in `src` property has been loaded.\n */\n @Event({ eventName: 'pod-os:resource-loaded' }) resourceLoadedEmitter: EventEmitter<string>;\n\n /**\n * Emitted when an error occurs during file operations.\n */\n @Event({ eventName: 'pod-os:error' }) errorEmitter: EventEmitter<Error>;\n\n componentWillLoad() {\n session.onChange('isLoggedIn', () => this.fetchBlob());\n this.initializeOsEmitter.emit(this.setOs);\n }\n\n setOs = async (os: PodOS) => {\n this.os = os;\n };\n\n @Listen('pod-os:document-modified')\n async handleDocumentModified(event: CustomEvent) {\n const { file, newContent } = event.detail;\n try {\n this.saveStatus = 'saving';\n const response = await this.os.files().putFile(file, newContent);\n if (response.ok) {\n this.saveStatus = 'idle';\n } else {\n this.saveStatus = 'failed';\n const error = new Error(`Failed to save file: ${response.status} ${response.statusText}`);\n this.errorEmitter.emit(error);\n }\n } catch (error) {\n this.saveStatus = 'failed';\n this.errorEmitter.emit(error);\n }\n }\n\n @Watch('os')\n @Watch('src')\n async fetchBlob() {\n try {\n this.loading = true;\n const file = await this.os.files().fetchFile(this.src);\n const thing = this.os.store.get(this.src);\n this.isEditable = thing?.editable;\n this.resourceLoadedEmitter.emit(this.src);\n if (file.blob()) {\n this.file = file;\n this.error = null;\n } else {\n this.brokenFile = file as BrokenFileData;\n }\n } catch (err) {\n this.error = err;\n } finally {\n this.loading = false;\n }\n }\n\n render() {\n if (this.loading) {\n return <ion-skeleton-text animated={true}></ion-skeleton-text>;\n }\n if (this.error) {\n return <div class=\"error\">{this.error.message}</div>;\n }\n if (this.brokenFile) {\n return <BrokenFile file={this.brokenFile} />;\n }\n if (this.file.blob().type === 'text/markdown') {\n return (\n <pos-markdown-document\n editable={this.isEditable}\n saveStatus={this.saveStatus}\n file={this.file}\n ></pos-markdown-document>\n );\n } else {\n return <iframe src={URL.createObjectURL(this.file.blob())}></iframe>;\n }\n }\n}\n"],"version":3}