@pallasoft/ps-input-components 2.1.0 → 3.0.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 (136) hide show
  1. package/dist/components/ps-calendar-header.js +4 -7
  2. package/dist/components/ps-cascader-input.js +1 -1
  3. package/dist/components/ps-checkbox-matrix.d.ts +13 -0
  4. package/dist/components/ps-checkbox-matrix.js +24 -0
  5. package/dist/components/ps-color-picker.js +2 -2
  6. package/dist/components/ps-combobox-input.js +1 -1
  7. package/dist/components/ps-date-input.js +1 -1
  8. package/dist/components/ps-date-preset-field.js +2 -2
  9. package/dist/components/ps-field-skeleton.js +1 -1
  10. package/dist/components/ps-file-picker.js +1 -1
  11. package/dist/components/ps-multi-select-input.js +2 -2
  12. package/dist/components/ps-phone-input.js +1 -1
  13. package/dist/components/ps-portable-text-editor.d.ts +1 -1
  14. package/dist/components/ps-portable-text-editor.js +1 -2
  15. package/dist/components/ps-portable-text-link-dialog.d.ts +2 -1
  16. package/dist/components/ps-portable-text-link-dialog.js +2 -2
  17. package/dist/components/ps-portable-text-toolbar.js +2 -7
  18. package/dist/components/ps-select-input.js +1 -1
  19. package/dist/components/ps-toggle.js +1 -1
  20. package/dist/components/ps-year-input.js +1 -1
  21. package/dist/constants/ps-calendar-header-classes.d.ts +6 -0
  22. package/dist/constants/ps-calendar-header-classes.js +9 -0
  23. package/dist/constants/ps-portable-text-editor-config.d.ts +10 -2
  24. package/dist/constants/ps-portable-text-editor-config.js +10 -2
  25. package/dist/esm/components/ps-calendar-header.js +4 -7
  26. package/dist/esm/components/ps-cascader-input.js +1 -1
  27. package/dist/esm/components/ps-checkbox-matrix.js +20 -0
  28. package/dist/esm/components/ps-color-picker.js +2 -2
  29. package/dist/esm/components/ps-combobox-input.js +1 -1
  30. package/dist/esm/components/ps-date-input.js +1 -1
  31. package/dist/esm/components/ps-date-preset-field.js +2 -2
  32. package/dist/esm/components/ps-field-skeleton.js +1 -1
  33. package/dist/esm/components/ps-file-picker.js +1 -1
  34. package/dist/esm/components/ps-multi-select-input.js +2 -2
  35. package/dist/esm/components/ps-phone-input.js +1 -1
  36. package/dist/esm/components/ps-portable-text-editor.js +1 -2
  37. package/dist/esm/components/ps-portable-text-link-dialog.js +2 -2
  38. package/dist/esm/components/ps-portable-text-toolbar.js +2 -7
  39. package/dist/esm/components/ps-select-input.js +1 -1
  40. package/dist/esm/components/ps-toggle.js +1 -1
  41. package/dist/esm/components/ps-year-input.js +1 -1
  42. package/dist/esm/constants/ps-calendar-header-classes.js +6 -0
  43. package/dist/esm/constants/ps-portable-text-editor-config.js +10 -2
  44. package/dist/esm/index.js +7 -0
  45. package/dist/esm/interfaces/ps-checkbox-matrix-cell.js +1 -0
  46. package/dist/esm/interfaces/ps-checkbox-matrix-column.js +1 -0
  47. package/dist/esm/interfaces/ps-checkbox-matrix-group.js +1 -0
  48. package/dist/esm/interfaces/ps-checkbox-matrix-labels.js +1 -0
  49. package/dist/esm/interfaces/ps-checkbox-matrix-row.js +1 -0
  50. package/dist/esm/portable-text-core/components/ps-portable-text-core-editor-stub.js +2 -0
  51. package/dist/esm/portable-text-core/components/ps-portable-text-core-editor.js +64 -0
  52. package/dist/esm/portable-text-core/components/ps-portable-text-core.js +5 -26
  53. package/dist/esm/portable-text-core/constants/ps-portable-text-core-config.js +29 -9
  54. package/dist/esm/portable-text-core/contexts/ps-portable-text-core-context.js +9 -0
  55. package/dist/esm/portable-text-core/hooks/use-ps-portable-text-link-form.js +11 -5
  56. package/dist/esm/portable-text-core/hooks/use-ps-portable-text-toolbar.js +17 -49
  57. package/dist/esm/portable-text-core/index.js +4 -0
  58. package/dist/esm/portable-text-core/interfaces/ps-portable-text-active-formats.js +1 -0
  59. package/dist/esm/portable-text-core/interfaces/ps-portable-text-block-draft.js +1 -0
  60. package/dist/esm/portable-text-core/interfaces/ps-portable-text-core-class-names.js +1 -0
  61. package/dist/esm/portable-text-core/interfaces/ps-portable-text-core-context-data.js +1 -0
  62. package/dist/esm/portable-text-core/interfaces/ps-portable-text-core-props.js +1 -0
  63. package/dist/esm/portable-text-core/interfaces/ps-portable-text-extension-options.js +1 -0
  64. package/dist/esm/portable-text-core/interfaces/ps-portable-text-span-draft.js +1 -0
  65. package/dist/esm/portable-text-core/interfaces/ps-portable-text-toolbar-state.js +1 -0
  66. package/dist/esm/portable-text-core/services/ps-portable-text-command-service.js +73 -0
  67. package/dist/esm/portable-text-core/services/ps-portable-text-converter-service.js +196 -0
  68. package/dist/esm/portable-text-core/services/ps-portable-text-editor-service.js +4 -0
  69. package/dist/esm/portable-text-core/services/ps-portable-text-extension-service.js +89 -0
  70. package/dist/esm/portable-text-engine/index.js +1 -0
  71. package/dist/esm/portable-text-engine/worker.js +1 -0
  72. package/dist/esm/services/ps-checkbox-matrix-service.js +28 -0
  73. package/dist/index.d.ts +7 -0
  74. package/dist/index.js +7 -0
  75. package/dist/interfaces/ps-checkbox-matrix-cell.d.ts +6 -0
  76. package/dist/interfaces/ps-checkbox-matrix-cell.js +2 -0
  77. package/dist/interfaces/ps-checkbox-matrix-column.d.ts +5 -0
  78. package/dist/interfaces/ps-checkbox-matrix-column.js +2 -0
  79. package/dist/interfaces/ps-checkbox-matrix-group.d.ts +6 -0
  80. package/dist/interfaces/ps-checkbox-matrix-group.js +2 -0
  81. package/dist/interfaces/ps-checkbox-matrix-labels.d.ts +9 -0
  82. package/dist/interfaces/ps-checkbox-matrix-labels.js +2 -0
  83. package/dist/interfaces/ps-checkbox-matrix-row.d.ts +6 -0
  84. package/dist/interfaces/ps-checkbox-matrix-row.js +2 -0
  85. package/dist/portable-text/index.d.ts +1 -1
  86. package/dist/portable-text-core/components/ps-portable-text-core-editor-stub.d.ts +2 -0
  87. package/dist/portable-text-core/components/ps-portable-text-core-editor-stub.js +6 -0
  88. package/dist/portable-text-core/components/ps-portable-text-core-editor.d.ts +2 -0
  89. package/dist/portable-text-core/components/ps-portable-text-core-editor.js +68 -0
  90. package/dist/portable-text-core/components/ps-portable-text-core.d.ts +2 -17
  91. package/dist/portable-text-core/components/ps-portable-text-core.js +3 -24
  92. package/dist/portable-text-core/constants/ps-portable-text-core-config.d.ts +36 -19
  93. package/dist/portable-text-core/constants/ps-portable-text-core-config.js +29 -9
  94. package/dist/portable-text-core/contexts/ps-portable-text-core-context.d.ts +2 -0
  95. package/dist/portable-text-core/contexts/ps-portable-text-core-context.js +12 -0
  96. package/dist/portable-text-core/hooks/use-ps-portable-text-link-form.d.ts +3 -1
  97. package/dist/portable-text-core/hooks/use-ps-portable-text-link-form.js +10 -4
  98. package/dist/portable-text-core/hooks/use-ps-portable-text-toolbar.d.ts +5 -10
  99. package/dist/portable-text-core/hooks/use-ps-portable-text-toolbar.js +17 -49
  100. package/dist/portable-text-core/index.d.ts +5 -1
  101. package/dist/portable-text-core/index.js +4 -0
  102. package/dist/portable-text-core/interfaces/ps-portable-text-active-formats.d.ts +10 -0
  103. package/dist/portable-text-core/interfaces/ps-portable-text-active-formats.js +2 -0
  104. package/dist/portable-text-core/interfaces/ps-portable-text-block-draft.d.ts +7 -0
  105. package/dist/portable-text-core/interfaces/ps-portable-text-block-draft.js +2 -0
  106. package/dist/portable-text-core/interfaces/ps-portable-text-core-class-names.d.ts +8 -0
  107. package/dist/portable-text-core/interfaces/ps-portable-text-core-class-names.js +2 -0
  108. package/dist/portable-text-core/interfaces/ps-portable-text-core-context-data.d.ts +9 -0
  109. package/dist/portable-text-core/interfaces/ps-portable-text-core-context-data.js +2 -0
  110. package/dist/portable-text-core/interfaces/ps-portable-text-core-props.d.ts +16 -0
  111. package/dist/portable-text-core/interfaces/ps-portable-text-core-props.js +2 -0
  112. package/dist/portable-text-core/interfaces/ps-portable-text-editor-labels.d.ts +1 -0
  113. package/dist/portable-text-core/interfaces/ps-portable-text-extension-options.d.ts +6 -0
  114. package/dist/portable-text-core/interfaces/ps-portable-text-extension-options.js +2 -0
  115. package/dist/portable-text-core/interfaces/ps-portable-text-span-draft.d.ts +4 -0
  116. package/dist/portable-text-core/interfaces/ps-portable-text-span-draft.js +2 -0
  117. package/dist/portable-text-core/interfaces/ps-portable-text-toolbar-state.d.ts +5 -0
  118. package/dist/portable-text-core/interfaces/ps-portable-text-toolbar-state.js +2 -0
  119. package/dist/portable-text-core/services/ps-portable-text-command-service.d.ts +14 -0
  120. package/dist/portable-text-core/services/ps-portable-text-command-service.js +77 -0
  121. package/dist/portable-text-core/services/ps-portable-text-converter-service.d.ts +18 -0
  122. package/dist/portable-text-core/services/ps-portable-text-converter-service.js +200 -0
  123. package/dist/portable-text-core/services/ps-portable-text-editor-service.d.ts +1 -0
  124. package/dist/portable-text-core/services/ps-portable-text-editor-service.js +4 -0
  125. package/dist/portable-text-core/services/ps-portable-text-extension-service.d.ts +8 -0
  126. package/dist/portable-text-core/services/ps-portable-text-extension-service.js +93 -0
  127. package/dist/portable-text-engine/index.d.ts +1 -0
  128. package/dist/portable-text-engine/index.js +17 -0
  129. package/dist/portable-text-engine/worker.d.ts +1 -0
  130. package/dist/portable-text-engine/worker.js +17 -0
  131. package/dist/services/ps-checkbox-matrix-service.d.ts +9 -0
  132. package/dist/services/ps-checkbox-matrix-service.js +32 -0
  133. package/package.json +30 -6
  134. package/dist/constants/ps-portable-text-editor-renderers.d.ts +0 -6
  135. package/dist/constants/ps-portable-text-editor-renderers.js +0 -32
  136. package/dist/esm/constants/ps-portable-text-editor-renderers.js +0 -29
@@ -0,0 +1,73 @@
1
+ import { PsPortableTextCoreConfig } from '../constants/ps-portable-text-core-config';
2
+ import { PsPortableTextEditorService } from './ps-portable-text-editor-service';
3
+ export class PsPortableTextCommandService {
4
+ static state(editor) {
5
+ return { active: this.active(editor), linkHref: this.linkHref(editor) };
6
+ }
7
+ static active(editor) {
8
+ const isActive = (name) => (editor === null ? false : editor.isActive(name));
9
+ const marks = PsPortableTextCoreConfig.decoratorMarks;
10
+ const decorators = PsPortableTextCoreConfig.decorators;
11
+ return {
12
+ bold: isActive(marks[decorators.bold]),
13
+ bulletedList: isActive(PsPortableTextCoreConfig.nodes.bulletList),
14
+ code: isActive(marks[decorators.code]),
15
+ italic: isActive(marks[decorators.italic]),
16
+ link: isActive(PsPortableTextCoreConfig.linkMark),
17
+ numberedList: isActive(PsPortableTextCoreConfig.nodes.orderedList),
18
+ quote: isActive(PsPortableTextCoreConfig.nodes.blockquote),
19
+ underline: isActive(marks[decorators.underline]),
20
+ };
21
+ }
22
+ static linkHref(editor) {
23
+ const href = editor === null ? undefined : editor.getAttributes(PsPortableTextCoreConfig.linkMark).href;
24
+ return typeof href === 'string' ? href : '';
25
+ }
26
+ static toggleDecorator(editor, decorator) {
27
+ const mark = PsPortableTextEditorService.lookup(PsPortableTextCoreConfig.decoratorMarks, decorator);
28
+ if (editor !== null && mark !== null)
29
+ editor.chain().focus().toggleMark(mark).run();
30
+ }
31
+ static toggleListItem(editor, listItem) {
32
+ const list = PsPortableTextEditorService.lookup(PsPortableTextCoreConfig.listNodes, listItem);
33
+ if (editor !== null && list !== null) {
34
+ editor.chain().focus().toggleList(list, PsPortableTextCoreConfig.nodes.listItem).run();
35
+ }
36
+ }
37
+ static toggleQuote(editor) {
38
+ if (editor !== null)
39
+ editor.chain().focus().toggleBlockquote().run();
40
+ }
41
+ static setLink(editor, href) {
42
+ if (editor === null)
43
+ return;
44
+ if (editor.state.selection.empty && !editor.isActive(PsPortableTextCoreConfig.linkMark)) {
45
+ editor
46
+ .chain()
47
+ .focus()
48
+ .insertContent({
49
+ type: PsPortableTextCoreConfig.nodes.text,
50
+ text: href.replace(PsPortableTextCoreConfig.mailtoPrefix, ''),
51
+ marks: [{ type: PsPortableTextCoreConfig.linkMark, attrs: { href } }],
52
+ })
53
+ .unsetMark(PsPortableTextCoreConfig.linkMark)
54
+ .run();
55
+ return;
56
+ }
57
+ editor
58
+ .chain()
59
+ .focus()
60
+ .extendMarkRange(PsPortableTextCoreConfig.linkMark)
61
+ .setLink({ href })
62
+ .run();
63
+ }
64
+ static removeLink(editor) {
65
+ if (editor !== null) {
66
+ editor.chain().focus().extendMarkRange(PsPortableTextCoreConfig.linkMark).unsetLink().run();
67
+ }
68
+ }
69
+ static focus(editor) {
70
+ if (editor !== null)
71
+ editor.commands.focus();
72
+ }
73
+ }
@@ -0,0 +1,196 @@
1
+ import { Common } from '@pallasoft/ps-models';
2
+ import { PsPortableTextCoreConfig } from '../constants/ps-portable-text-core-config';
3
+ import { PsPortableTextEditorService } from './ps-portable-text-editor-service';
4
+ export class PsPortableTextConverterService {
5
+ static toDocument(blocks) {
6
+ const content = [];
7
+ let lists = [];
8
+ let quote = null;
9
+ (Array.isArray(blocks) ? blocks : [])
10
+ .filter((block) => block._type === Common.PortableTextConfig.blockType)
11
+ .forEach((block) => {
12
+ const paragraph = this.paragraph(block);
13
+ const listNode = this.listNode(block.listItem);
14
+ if (listNode === null) {
15
+ lists = [];
16
+ if (block.style !== PsPortableTextCoreConfig.styles.blockquote) {
17
+ quote = null;
18
+ content.push(paragraph);
19
+ return;
20
+ }
21
+ if (quote === null) {
22
+ quote = { type: PsPortableTextCoreConfig.nodes.blockquote, content: [] };
23
+ content.push(quote);
24
+ }
25
+ this.children(quote).push(paragraph);
26
+ return;
27
+ }
28
+ quote = null;
29
+ const level = Math.min(this.level(block.level), lists.length + 1);
30
+ const open = lists.slice(0, level);
31
+ lists =
32
+ open.length === level && open[level - 1].type !== listNode ? open.slice(0, -1) : open;
33
+ if (lists.length < level) {
34
+ const list = { type: listNode, content: [] };
35
+ const parent = lists[lists.length - 1];
36
+ if (parent === undefined)
37
+ content.push(list);
38
+ else
39
+ this.children(this.children(parent)[this.children(parent).length - 1]).push(list);
40
+ lists = [...lists, list];
41
+ }
42
+ this.children(lists[level - 1]).push({
43
+ type: PsPortableTextCoreConfig.nodes.listItem,
44
+ content: [paragraph],
45
+ });
46
+ });
47
+ return {
48
+ type: PsPortableTextCoreConfig.nodes.document,
49
+ content: content.length === 0 ? [{ type: PsPortableTextCoreConfig.nodes.paragraph }] : content,
50
+ };
51
+ }
52
+ static toBlocks(document) {
53
+ const drafts = this.children(document).flatMap((node) => this.drafts(node, 1));
54
+ const isBlank = drafts.length === 1 &&
55
+ drafts[0].listItem === undefined &&
56
+ drafts[0].style === PsPortableTextCoreConfig.styles.normal &&
57
+ this.children(drafts[0].paragraph).length === 0;
58
+ return isBlank
59
+ ? []
60
+ : drafts.map((draft, index) => this.block(draft, `${PsPortableTextCoreConfig.keyPrefix.block}${index}`));
61
+ }
62
+ static drafts(node, level) {
63
+ if (node.type === PsPortableTextCoreConfig.nodes.paragraph) {
64
+ return [{ paragraph: node, style: PsPortableTextCoreConfig.styles.normal }];
65
+ }
66
+ if (node.type === PsPortableTextCoreConfig.nodes.blockquote) {
67
+ return this.children(node)
68
+ .filter((child) => child.type === PsPortableTextCoreConfig.nodes.paragraph)
69
+ .map((paragraph) => ({ paragraph, style: PsPortableTextCoreConfig.styles.blockquote }));
70
+ }
71
+ const listItem = this.listItem(node.type);
72
+ if (listItem === null)
73
+ return [];
74
+ return this.children(node).flatMap((item) => this.children(item).flatMap((child) => child.type === PsPortableTextCoreConfig.nodes.paragraph
75
+ ? [
76
+ {
77
+ level: Math.min(level, Common.PortableTextConfig.maxListLevel),
78
+ listItem,
79
+ paragraph: child,
80
+ style: PsPortableTextCoreConfig.styles.normal,
81
+ },
82
+ ]
83
+ : this.drafts(child, level + 1)));
84
+ }
85
+ static block(draft, key) {
86
+ const hrefs = Array.from(new Set(this.children(draft.paragraph).flatMap((node) => this.marks(node)
87
+ .filter((mark) => mark.type === PsPortableTextCoreConfig.linkMark)
88
+ .map((mark) => this.href(mark))
89
+ .filter((href) => href !== null))));
90
+ const markDefs = hrefs.map((href, index) => ({
91
+ _key: `${key}${PsPortableTextCoreConfig.keyPrefix.link}${index}`,
92
+ _type: PsPortableTextCoreConfig.linkAnnotation,
93
+ href,
94
+ }));
95
+ const spans = this.spans(draft.paragraph, markDefs);
96
+ const children = (spans.length === 0 ? [{ marks: [], text: '' }] : spans).map((span, index) => ({
97
+ _key: `${key}${PsPortableTextCoreConfig.keyPrefix.span}${index}`,
98
+ _type: Common.PortableTextConfig.spanType,
99
+ marks: span.marks,
100
+ text: span.text,
101
+ }));
102
+ const base = {
103
+ _key: key,
104
+ _type: Common.PortableTextConfig.blockType,
105
+ children,
106
+ markDefs,
107
+ style: draft.style,
108
+ };
109
+ return draft.listItem === undefined
110
+ ? base
111
+ : { ...base, level: draft.level, listItem: draft.listItem };
112
+ }
113
+ static spans(paragraph, markDefs) {
114
+ return this.children(paragraph).reduce((spans, node) => {
115
+ const previous = spans[spans.length - 1];
116
+ const isBreak = node.type === PsPortableTextCoreConfig.nodes.hardBreak;
117
+ if (!isBreak && (node.type !== PsPortableTextCoreConfig.nodes.text || !node.text)) {
118
+ return spans;
119
+ }
120
+ const marks = this.spanMarks(node, markDefs);
121
+ const text = isBreak ? PsPortableTextCoreConfig.lineBreak : String(node.text);
122
+ return previous !== undefined && this.isSame(previous.marks, marks)
123
+ ? [...spans.slice(0, -1), { marks, text: previous.text + text }]
124
+ : [...spans, { marks, text }];
125
+ }, []);
126
+ }
127
+ static spanMarks(node, markDefs) {
128
+ const types = this.marks(node).map((mark) => mark.type);
129
+ const decorators = Common.PortableTextConfig.decorators.filter((decorator) => types.includes(PsPortableTextCoreConfig.decoratorMarks[decorator]));
130
+ const links = this.marks(node)
131
+ .filter((mark) => mark.type === PsPortableTextCoreConfig.linkMark)
132
+ .map((mark) => markDefs.find((definition) => definition.href === this.href(mark)))
133
+ .filter((definition) => definition !== undefined)
134
+ .map((definition) => definition._key);
135
+ return [...decorators, ...links];
136
+ }
137
+ static paragraph(block) {
138
+ const links = new Map((Array.isArray(block.markDefs) ? block.markDefs : [])
139
+ .filter((definition) => definition._type === PsPortableTextCoreConfig.linkAnnotation)
140
+ .map((definition) => [
141
+ definition._key,
142
+ typeof definition.href === 'string'
143
+ ? PsPortableTextEditorService.normalizeLink(definition.href)
144
+ : null,
145
+ ]));
146
+ const content = (Array.isArray(block.children) ? block.children : [])
147
+ .filter((child) => child._type === Common.PortableTextConfig.spanType && typeof child.text === 'string')
148
+ .flatMap((child) => {
149
+ const marks = (Array.isArray(child.marks) ? child.marks : [])
150
+ .filter((mark) => typeof mark === 'string')
151
+ .flatMap((mark) => {
152
+ const decorator = PsPortableTextEditorService.lookup(PsPortableTextCoreConfig.decoratorMarks, mark);
153
+ const href = links.get(mark);
154
+ if (decorator !== null)
155
+ return [{ type: decorator }];
156
+ return typeof href === 'string'
157
+ ? [{ type: PsPortableTextCoreConfig.linkMark, attrs: { href } }]
158
+ : [];
159
+ });
160
+ return String(child.text)
161
+ .split(PsPortableTextCoreConfig.lineBreak)
162
+ .flatMap((text, index) => [
163
+ ...(index === 0 ? [] : [{ type: PsPortableTextCoreConfig.nodes.hardBreak, marks }]),
164
+ ...(text === '' ? [] : [{ type: PsPortableTextCoreConfig.nodes.text, text, marks }]),
165
+ ]);
166
+ });
167
+ return content.length === 0
168
+ ? { type: PsPortableTextCoreConfig.nodes.paragraph }
169
+ : { type: PsPortableTextCoreConfig.nodes.paragraph, content };
170
+ }
171
+ static listNode(listItem) {
172
+ return PsPortableTextEditorService.lookup(PsPortableTextCoreConfig.listNodes, listItem);
173
+ }
174
+ static listItem(type) {
175
+ const match = Object.entries(PsPortableTextCoreConfig.listNodes).find(([, node]) => node === type);
176
+ return match === undefined ? null : match[0];
177
+ }
178
+ static level(level) {
179
+ return typeof level === 'number' && Number.isInteger(level)
180
+ ? Math.max(1, Math.min(level, Common.PortableTextConfig.maxListLevel))
181
+ : 1;
182
+ }
183
+ static href(mark) {
184
+ const href = mark.attrs === undefined ? undefined : mark.attrs.href;
185
+ return typeof href === 'string' ? PsPortableTextEditorService.normalizeLink(href) : null;
186
+ }
187
+ static marks(node) {
188
+ return Array.isArray(node.marks) ? node.marks : [];
189
+ }
190
+ static children(node) {
191
+ return Array.isArray(node.content) ? node.content : [];
192
+ }
193
+ static isSame(first, second) {
194
+ return first.length === second.length && first.every((mark, index) => mark === second[index]);
195
+ }
196
+ }
@@ -27,4 +27,8 @@ export class PsPortableTextEditorService {
27
27
  static isSame(first, second) {
28
28
  return JSON.stringify(first) === JSON.stringify(second);
29
29
  }
30
+ static lookup(record, key) {
31
+ const match = Object.entries(record).find(([name]) => name === key);
32
+ return match === undefined ? null : match[1];
33
+ }
30
34
  }
@@ -0,0 +1,89 @@
1
+ import { Common } from '@pallasoft/ps-models';
2
+ import { Extension } from '@tiptap/core';
3
+ import { Blockquote } from '@tiptap/extension-blockquote';
4
+ import { Bold } from '@tiptap/extension-bold';
5
+ import { Code } from '@tiptap/extension-code';
6
+ import { Document } from '@tiptap/extension-document';
7
+ import { HardBreak } from '@tiptap/extension-hard-break';
8
+ import { Italic } from '@tiptap/extension-italic';
9
+ import { Link } from '@tiptap/extension-link';
10
+ import { BulletList, ListItem, ListKeymap, OrderedList } from '@tiptap/extension-list';
11
+ import { Paragraph } from '@tiptap/extension-paragraph';
12
+ import { Text } from '@tiptap/extension-text';
13
+ import { Underline } from '@tiptap/extension-underline';
14
+ import { Placeholder, UndoRedo } from '@tiptap/extensions';
15
+ import { PsPortableTextCoreConfig } from '../constants/ps-portable-text-core-config';
16
+ import { PsPortableTextEditorService } from './ps-portable-text-editor-service';
17
+ export class PsPortableTextExtensionService {
18
+ static extensions({ classNames, onLinkShortcut, placeholder, }) {
19
+ return [
20
+ Document,
21
+ Paragraph,
22
+ Text,
23
+ HardBreak,
24
+ Bold,
25
+ Italic,
26
+ Underline,
27
+ Code.extend({ excludes: Code.name }).configure({
28
+ HTMLAttributes: { class: classNames.code },
29
+ }),
30
+ Blockquote.extend({ content: PsPortableTextCoreConfig.blockquoteContent }).configure({
31
+ HTMLAttributes: { class: classNames.blockquote },
32
+ }),
33
+ BulletList.configure({ HTMLAttributes: { class: classNames.bulletList } }),
34
+ OrderedList.configure({ HTMLAttributes: { class: classNames.orderedList } }),
35
+ ListItem.extend({
36
+ content: PsPortableTextCoreConfig.listItemContent,
37
+ addKeyboardShortcuts() {
38
+ return {
39
+ ...this.parent?.(),
40
+ [PsPortableTextCoreConfig.shortcuts.nest]: () => PsPortableTextExtensionService.nest(this.editor),
41
+ [PsPortableTextCoreConfig.shortcuts.unnest]: () => PsPortableTextExtensionService.unnest(this.editor),
42
+ };
43
+ },
44
+ }),
45
+ ListKeymap,
46
+ Link.configure({
47
+ autolink: true,
48
+ defaultProtocol: PsPortableTextCoreConfig.defaultLinkProtocol,
49
+ HTMLAttributes: { class: classNames.link },
50
+ isAllowedUri: (url, context) => context.defaultValidate(url) && PsPortableTextEditorService.normalizeLink(url) !== null,
51
+ linkOnPaste: true,
52
+ openOnClick: false,
53
+ }),
54
+ Placeholder.configure({
55
+ emptyEditorClass: classNames.placeholder,
56
+ placeholder: ({ editor }) => (editor.isEmpty ? placeholder : ''),
57
+ }),
58
+ UndoRedo,
59
+ Extension.create({
60
+ name: PsPortableTextCoreConfig.linkShortcutExtension,
61
+ addKeyboardShortcuts: () => ({
62
+ [PsPortableTextCoreConfig.shortcuts.link]: () => {
63
+ onLinkShortcut();
64
+ return true;
65
+ },
66
+ }),
67
+ }),
68
+ ];
69
+ }
70
+ static listDepth(editor) {
71
+ const { $from } = editor.state.selection;
72
+ return Array.from({ length: $from.depth }, (_, index) => $from.node(index + 1)).filter((node) => node.type.name === PsPortableTextCoreConfig.nodes.listItem).length;
73
+ }
74
+ static nest(editor) {
75
+ const depth = PsPortableTextExtensionService.listDepth(editor);
76
+ if (depth === 0)
77
+ return false;
78
+ if (depth < Common.PortableTextConfig.maxListLevel) {
79
+ editor.commands.sinkListItem(PsPortableTextCoreConfig.nodes.listItem);
80
+ }
81
+ return true;
82
+ }
83
+ static unnest(editor) {
84
+ if (PsPortableTextExtensionService.listDepth(editor) === 0)
85
+ return false;
86
+ editor.commands.liftListItem(PsPortableTextCoreConfig.nodes.listItem);
87
+ return true;
88
+ }
89
+ }
@@ -0,0 +1 @@
1
+ export * from '../portable-text-core/components/ps-portable-text-core-editor';
@@ -0,0 +1 @@
1
+ export * from '../portable-text-core/components/ps-portable-text-core-editor-stub';
@@ -0,0 +1,28 @@
1
+ export class PsCheckboxMatrixService {
2
+ static values(group) {
3
+ return group.rows.flatMap((row) => row.cells.map((cell) => cell.value));
4
+ }
5
+ static enabledValues(group) {
6
+ return group.rows.flatMap((row) => row.cells.filter((cell) => !cell.isDisabled).map((cell) => cell.value));
7
+ }
8
+ static selectedCount(group, value) {
9
+ return PsCheckboxMatrixService.values(group).filter((item) => value.includes(item)).length;
10
+ }
11
+ static toggle(value, item, isSelected) {
12
+ return isSelected
13
+ ? value.includes(item)
14
+ ? value
15
+ : [...value, item]
16
+ : value.filter((existing) => existing !== item);
17
+ }
18
+ static toggleGroup(value, group, isSelected) {
19
+ const enabled = PsCheckboxMatrixService.enabledValues(group);
20
+ return isSelected
21
+ ? [...value, ...enabled.filter((item) => !value.includes(item))]
22
+ : value.filter((item) => !enabled.includes(item));
23
+ }
24
+ static isGroupComplete(group, value) {
25
+ const enabled = PsCheckboxMatrixService.enabledValues(group);
26
+ return enabled.length > 0 && enabled.every((item) => value.includes(item));
27
+ }
28
+ }
package/dist/index.d.ts CHANGED
@@ -47,3 +47,10 @@ export * from './constants/ps-select-with-create-config';
47
47
  export * from './interfaces/ps-date-preset-data';
48
48
  export * from './components/ps-option-card-group';
49
49
  export * from './interfaces/ps-option-card-data';
50
+ export * from './components/ps-checkbox-matrix';
51
+ export * from './interfaces/ps-checkbox-matrix-cell';
52
+ export * from './interfaces/ps-checkbox-matrix-column';
53
+ export * from './interfaces/ps-checkbox-matrix-group';
54
+ export * from './interfaces/ps-checkbox-matrix-labels';
55
+ export * from './interfaces/ps-checkbox-matrix-row';
56
+ export * from './services/ps-checkbox-matrix-service';
package/dist/index.js CHANGED
@@ -63,3 +63,10 @@ __exportStar(require("./constants/ps-select-with-create-config"), exports);
63
63
  __exportStar(require("./interfaces/ps-date-preset-data"), exports);
64
64
  __exportStar(require("./components/ps-option-card-group"), exports);
65
65
  __exportStar(require("./interfaces/ps-option-card-data"), exports);
66
+ __exportStar(require("./components/ps-checkbox-matrix"), exports);
67
+ __exportStar(require("./interfaces/ps-checkbox-matrix-cell"), exports);
68
+ __exportStar(require("./interfaces/ps-checkbox-matrix-column"), exports);
69
+ __exportStar(require("./interfaces/ps-checkbox-matrix-group"), exports);
70
+ __exportStar(require("./interfaces/ps-checkbox-matrix-labels"), exports);
71
+ __exportStar(require("./interfaces/ps-checkbox-matrix-row"), exports);
72
+ __exportStar(require("./services/ps-checkbox-matrix-service"), exports);
@@ -0,0 +1,6 @@
1
+ export interface PsCheckboxMatrixCell {
2
+ columnId: string;
3
+ isDisabled: boolean;
4
+ reason: string | null;
5
+ value: string;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ export interface PsCheckboxMatrixColumn {
2
+ hint: string | null;
3
+ id: string;
4
+ label: string;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import type { PsCheckboxMatrixRow } from './ps-checkbox-matrix-row';
2
+ export interface PsCheckboxMatrixGroup {
3
+ id: string;
4
+ label: string;
5
+ rows: PsCheckboxMatrixRow[];
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,9 @@
1
+ import type { PsCheckboxMatrixColumn } from './ps-checkbox-matrix-column';
2
+ import type { PsCheckboxMatrixGroup } from './ps-checkbox-matrix-group';
3
+ import type { PsCheckboxMatrixRow } from './ps-checkbox-matrix-row';
4
+ export interface PsCheckboxMatrixLabels {
5
+ cell: (row: PsCheckboxMatrixRow, column: PsCheckboxMatrixColumn) => string;
6
+ count: (selected: number, total: number) => string;
7
+ rowHeading: string;
8
+ selectGroup: (group: PsCheckboxMatrixGroup) => string;
9
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import type { PsCheckboxMatrixCell } from './ps-checkbox-matrix-cell';
2
+ export interface PsCheckboxMatrixRow {
3
+ cells: PsCheckboxMatrixCell[];
4
+ id: string;
5
+ label: string;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,3 +1,3 @@
1
1
  export * from '../components/ps-portable-text-editor';
2
2
  export * from '../portable-text-core/interfaces/ps-portable-text-editor-labels';
3
- export type { PortableTextBlock } from '@portabletext/editor';
3
+ export type { PortableTextBlock } from '@portabletext/schema';
@@ -0,0 +1,2 @@
1
+ import type { PsPortableTextCoreProps } from '../interfaces/ps-portable-text-core-props';
2
+ export declare const PsPortableTextCoreEditor: ({ className, fallback }: PsPortableTextCoreProps) => import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsPortableTextCoreEditor = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const PsPortableTextCoreEditor = ({ className, fallback }) => ((0, jsx_runtime_1.jsx)("div", { className: className, children: fallback }));
6
+ exports.PsPortableTextCoreEditor = PsPortableTextCoreEditor;
@@ -0,0 +1,2 @@
1
+ import type { PsPortableTextCoreProps } from '../interfaces/ps-portable-text-core-props';
2
+ export declare const PsPortableTextCoreEditor: ({ className, classNames, disabled, editableClassName, label, minRows, onChange, placeholder, toolbar, value, }: PsPortableTextCoreProps) => import("react").JSX.Element;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsPortableTextCoreEditor = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const react_2 = require("@tiptap/react");
7
+ const ps_portable_text_core_context_1 = require("../contexts/ps-portable-text-core-context");
8
+ const ps_portable_text_command_service_1 = require("../services/ps-portable-text-command-service");
9
+ const ps_portable_text_converter_service_1 = require("../services/ps-portable-text-converter-service");
10
+ const ps_portable_text_editor_service_1 = require("../services/ps-portable-text-editor-service");
11
+ const ps_portable_text_extension_service_1 = require("../services/ps-portable-text-extension-service");
12
+ const PsPortableTextCoreEditor = ({ className, classNames, disabled = false, editableClassName = '', label, minRows = 4, onChange, placeholder = '', toolbar, value, }) => {
13
+ const [isLinkOpen, setIsLinkOpen] = (0, react_1.useState)(false);
14
+ const lastValue = (0, react_1.useRef)(value);
15
+ const editor = (0, react_2.useEditor)({
16
+ content: ps_portable_text_converter_service_1.PsPortableTextConverterService.toDocument(value),
17
+ editable: !disabled,
18
+ editorProps: {
19
+ attributes: {
20
+ ...(label === undefined ? {} : { 'aria-label': label }),
21
+ 'aria-multiline': 'true',
22
+ 'class': editableClassName,
23
+ 'role': 'textbox',
24
+ 'style': `min-height: ${ps_portable_text_editor_service_1.PsPortableTextEditorService.minHeight(minRows)}`,
25
+ },
26
+ },
27
+ extensions: ps_portable_text_extension_service_1.PsPortableTextExtensionService.extensions({
28
+ classNames,
29
+ onLinkShortcut: () => setIsLinkOpen(true),
30
+ placeholder,
31
+ }),
32
+ immediatelyRender: true,
33
+ }, []);
34
+ const state = (0, react_2.useEditorState)({
35
+ editor,
36
+ selector: ({ editor: current }) => ps_portable_text_command_service_1.PsPortableTextCommandService.state(current),
37
+ });
38
+ (0, react_1.useEffect)(() => {
39
+ editor.setEditable(!disabled, false);
40
+ }, [editor, disabled]);
41
+ (0, react_1.useEffect)(() => {
42
+ const update = () => {
43
+ const next = ps_portable_text_converter_service_1.PsPortableTextConverterService.toBlocks(editor.getJSON());
44
+ lastValue.current = next;
45
+ onChange(next);
46
+ };
47
+ editor.on('update', update);
48
+ return () => {
49
+ editor.off('update', update);
50
+ };
51
+ }, [editor, onChange]);
52
+ (0, react_1.useEffect)(() => {
53
+ if (ps_portable_text_editor_service_1.PsPortableTextEditorService.isSame(value, lastValue.current))
54
+ return;
55
+ lastValue.current = value;
56
+ editor.commands.setContent(ps_portable_text_converter_service_1.PsPortableTextConverterService.toDocument(value), {
57
+ emitUpdate: false,
58
+ });
59
+ }, [editor, value]);
60
+ return ((0, jsx_runtime_1.jsx)("div", { className: className, children: (0, jsx_runtime_1.jsxs)(ps_portable_text_core_context_1.PsPortableTextCoreContext.Provider, { value: {
61
+ closeLink: () => setIsLinkOpen(false),
62
+ editor,
63
+ isLinkOpen,
64
+ openLink: () => setIsLinkOpen(true),
65
+ state,
66
+ }, children: [toolbar, (0, jsx_runtime_1.jsx)(react_2.EditorContent, { editor: editor })] }) }));
67
+ };
68
+ exports.PsPortableTextCoreEditor = PsPortableTextCoreEditor;
@@ -1,17 +1,2 @@
1
- import { type ReactNode } from 'react';
2
- import { type PortableTextBlock, type RenderAnnotationFunction, type RenderBlockFunction, type RenderDecoratorFunction, type RenderPlaceholderFunction } from '@portabletext/editor';
3
- export interface PsPortableTextCoreProps {
4
- className?: string;
5
- disabled?: boolean;
6
- editableClassName?: string;
7
- fallback?: ReactNode;
8
- minRows?: number;
9
- onChange: (value: PortableTextBlock[]) => void;
10
- renderAnnotation?: RenderAnnotationFunction;
11
- renderBlock?: RenderBlockFunction;
12
- renderDecorator?: RenderDecoratorFunction;
13
- renderPlaceholder?: RenderPlaceholderFunction;
14
- toolbar?: ReactNode;
15
- value: PortableTextBlock[];
16
- }
17
- export declare const PsPortableTextCore: ({ className, disabled, editableClassName, fallback, minRows, onChange, renderAnnotation, renderBlock, renderDecorator, renderPlaceholder, toolbar, value, }: PsPortableTextCoreProps) => import("react").JSX.Element;
1
+ import type { PsPortableTextCoreProps } from '../interfaces/ps-portable-text-core-props';
2
+ export declare const PsPortableTextCore: (props: PsPortableTextCoreProps) => import("react").JSX.Element;
@@ -3,33 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsPortableTextCore = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
- const editor_1 = require("@portabletext/editor");
7
- const plugins_1 = require("@portabletext/editor/plugins");
8
- const ps_portable_text_core_config_1 = require("../constants/ps-portable-text-core-config");
9
- const ps_portable_text_editor_service_1 = require("../services/ps-portable-text-editor-service");
10
- const PsPortableTextCore = ({ className, disabled = false, editableClassName, fallback, minRows = 4, onChange, renderAnnotation, renderBlock, renderDecorator, renderPlaceholder, toolbar, value, }) => {
6
+ const portable_text_engine_1 = require("@pallasoft/ps-input-components/portable-text-engine");
7
+ const PsPortableTextCore = (props) => {
11
8
  const [isMounted, setIsMounted] = (0, react_1.useState)(false);
12
- const [version, setVersion] = (0, react_1.useState)(0);
13
- const lastValue = (0, react_1.useRef)(value);
14
9
  (0, react_1.useEffect)(() => {
15
10
  setIsMounted(true);
16
11
  }, []);
17
- (0, react_1.useEffect)(() => {
18
- if (ps_portable_text_editor_service_1.PsPortableTextEditorService.isSame(value, lastValue.current))
19
- return;
20
- lastValue.current = value;
21
- setVersion((current) => current + 1);
22
- }, [value]);
23
- return ((0, jsx_runtime_1.jsx)("div", { className: className, children: isMounted ? ((0, jsx_runtime_1.jsxs)(editor_1.EditorProvider, { initialConfig: {
24
- initialValue: value,
25
- readOnly: disabled,
26
- schemaDefinition: ps_portable_text_core_config_1.PsPortableTextCoreConfig.schemaDefinition,
27
- }, children: [(0, jsx_runtime_1.jsx)(plugins_1.EventListenerPlugin, { on: (event) => {
28
- if (event.type !== 'mutation')
29
- return;
30
- const next = Array.isArray(event.value) ? event.value : [];
31
- lastValue.current = next;
32
- onChange(next);
33
- } }), toolbar, (0, jsx_runtime_1.jsx)(editor_1.PortableTextEditable, { className: editableClassName, readOnly: disabled, renderAnnotation: renderAnnotation, renderBlock: renderBlock, renderDecorator: renderDecorator, renderPlaceholder: renderPlaceholder, style: { minHeight: ps_portable_text_editor_service_1.PsPortableTextEditorService.minHeight(minRows) } })] }, version)) : (fallback) }));
12
+ return isMounted ? ((0, jsx_runtime_1.jsx)(portable_text_engine_1.PsPortableTextCoreEditor, { ...props })) : ((0, jsx_runtime_1.jsx)("div", { className: props.className, children: props.fallback }));
34
13
  };
35
14
  exports.PsPortableTextCore = PsPortableTextCore;