ariadne_view_components 0.0.18 → 0.0.19

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -0
  3. data/app/assets/builds/ariadne_view_components.css +2243 -0
  4. data/app/assets/javascripts/ariadne_view_components.js +2 -2
  5. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  6. data/app/assets/javascripts/rich-text-area-component.d.ts +2 -0
  7. data/app/components/ariadne/ariadne-form-with.d.ts +20 -0
  8. data/app/components/ariadne/ariadne-form-with.js +85 -0
  9. data/app/components/ariadne/ariadne-form.d.ts +22 -0
  10. data/app/components/ariadne/ariadne-form.js +84 -0
  11. data/app/components/ariadne/ariadne.d.ts +2 -0
  12. data/app/components/ariadne/ariadne.js +16 -0
  13. data/app/components/ariadne/base_button.rb +2 -2
  14. data/app/components/ariadne/clipboard-copy-component.d.ts +4 -0
  15. data/app/components/ariadne/clipboard-copy-component.js +18 -0
  16. data/app/components/ariadne/clipboard_copy_component.d.ts +4 -0
  17. data/app/components/ariadne/clipboard_copy_component.js +18 -0
  18. data/app/components/ariadne/comment_component.html.erb +2 -2
  19. data/app/components/ariadne/component.rb +4 -0
  20. data/app/components/ariadne/inline_flex_component.rb +2 -2
  21. data/app/components/ariadne/panel_bar_component.html.erb +1 -1
  22. data/app/components/ariadne/panel_bar_component.rb +1 -0
  23. data/app/components/ariadne/rich-text-area-component.d.ts +6 -0
  24. data/app/components/ariadne/rich-text-area-component.js +36 -0
  25. data/app/components/ariadne/rich-text-area-component.ts +22 -9
  26. data/app/components/ariadne/rich_text_area_component.html.erb +1 -1
  27. data/app/components/ariadne/slideover-component.d.ts +9 -0
  28. data/app/components/ariadne/slideover-component.js +10 -0
  29. data/app/components/ariadne/slideover-component.ts +0 -9
  30. data/app/components/ariadne/slideover_component.d.ts +9 -0
  31. data/app/components/ariadne/slideover_component.html.erb +6 -8
  32. data/app/components/ariadne/slideover_component.js +19 -0
  33. data/app/components/ariadne/slideover_component.rb +9 -24
  34. data/app/components/ariadne/tab-component.js +1 -0
  35. data/app/components/ariadne/tab-container-component copy.d.ts +1 -0
  36. data/app/components/ariadne/tab-container-component copy.js +23 -0
  37. data/app/components/ariadne/tab-container-component.d.ts +1 -0
  38. data/app/components/ariadne/tab-container-component.js +23 -0
  39. data/app/components/ariadne/tab-nav-component.d.ts +9 -0
  40. data/app/components/ariadne/tab-nav-component.js +32 -0
  41. data/app/components/ariadne/tab_component.rb +0 -1
  42. data/app/components/ariadne/tab_container_component.erb +1 -1
  43. data/app/components/ariadne/tab_container_component.rb +2 -1
  44. data/app/components/ariadne/tabs-component.d.ts +0 -0
  45. data/app/components/ariadne/tabs-component.js +1 -0
  46. data/app/components/ariadne/time-ago-component.d.ts +1 -0
  47. data/app/components/ariadne/time-ago-component.js +1 -0
  48. data/app/components/ariadne/time_ago_component.d.ts +1 -0
  49. data/app/components/ariadne/time_ago_component.js +1 -0
  50. data/app/components/ariadne/tooltip-component.d.ts +24 -0
  51. data/app/components/ariadne/tooltip-component.js +42 -0
  52. data/lib/ariadne/view_components/version.rb +1 -1
  53. data/static/arguments.yml +0 -4
  54. data/static/classes.yml +3 -5
  55. data/static/constants.json +7 -8
  56. metadata +38 -6
@@ -1,4 +1,6 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
  export default class RichTextArea extends Controller {
3
+ static targets: string[];
4
+ readonly editorTargets: [HTMLDivElement];
3
5
  connect(): void;
4
6
  }
@@ -0,0 +1,20 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ import { TemplateResult } from 'lit-html';
3
+ declare type HTMLFormField = HTMLInputElement | HTMLButtonElement | HTMLSelectElement | HTMLTextAreaElement;
4
+ export default class AriadneFormWith extends Controller {
5
+ connect(): void;
6
+ disconnect(): void;
7
+ onBlur: (event: Event) => void;
8
+ onSubmit: (event: Event) => void;
9
+ validateForm(): boolean;
10
+ validateField(field: HTMLFormField): boolean;
11
+ shouldValidateField(field: HTMLFormField): boolean;
12
+ refreshErrorForInvalidField(field: HTMLFormField, isValid: boolean): void;
13
+ removeExistingErrorMessage(field: HTMLFormField): void;
14
+ showErrorForInvalidField(field: HTMLFormField): void;
15
+ buildFieldErrorHtml(field: HTMLFormField): string;
16
+ get formFields(): HTMLFormField[];
17
+ get firstInvalidField(): HTMLFormField | undefined;
18
+ getRenderString: (data: TemplateResult) => string;
19
+ }
20
+ export {};
@@ -0,0 +1,85 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ import { html } from 'lit-html';
3
+ export default class AriadneFormWith extends Controller {
4
+ constructor() {
5
+ super(...arguments);
6
+ this.onBlur = (event) => {
7
+ this.validateField(event.target);
8
+ };
9
+ this.onSubmit = (event) => {
10
+ var _a;
11
+ if (!this.validateForm()) {
12
+ event.preventDefault();
13
+ (_a = this.firstInvalidField) === null || _a === void 0 ? void 0 : _a.focus();
14
+ }
15
+ };
16
+ this.getRenderString = (data) => {
17
+ const { strings, values } = data;
18
+ const v = [...values, ''].map(e => (typeof e === 'object' ? this.getRenderString(e) : e));
19
+ return strings.reduce((acc, s, i) => acc + s + v[i], '');
20
+ };
21
+ }
22
+ connect() {
23
+ this.element.setAttribute('novalidate', 'true');
24
+ this.element.addEventListener('blur', this.onBlur, true);
25
+ this.element.addEventListener('submit', this.onSubmit);
26
+ this.element.addEventListener('ajax:beforeSend', this.onSubmit);
27
+ }
28
+ disconnect() {
29
+ this.element.removeEventListener('blur', this.onBlur);
30
+ this.element.removeEventListener('submit', this.onSubmit);
31
+ this.element.removeEventListener('ajax:beforeSend', this.onSubmit);
32
+ }
33
+ validateForm() {
34
+ let isValid = true;
35
+ // Not using `find` because we want to validate all the fields
36
+ for (const field of this.formFields) {
37
+ if (this.shouldValidateField(field) && !this.validateField(field))
38
+ isValid = false;
39
+ }
40
+ return isValid;
41
+ }
42
+ validateField(field) {
43
+ if (!this.shouldValidateField(field))
44
+ return true;
45
+ const isValid = field.checkValidity();
46
+ field.classList.toggle('invalid', !isValid);
47
+ this.refreshErrorForInvalidField(field, isValid);
48
+ return isValid;
49
+ }
50
+ shouldValidateField(field) {
51
+ return !field.disabled && !['file', 'reset', 'submit', 'button'].includes(field.type);
52
+ }
53
+ refreshErrorForInvalidField(field, isValid) {
54
+ this.removeExistingErrorMessage(field);
55
+ if (!isValid)
56
+ this.showErrorForInvalidField(field);
57
+ }
58
+ removeExistingErrorMessage(field) {
59
+ var _a;
60
+ const fieldContainer = field.closest('.field');
61
+ if (!fieldContainer)
62
+ return;
63
+ const existingErrorMessageElement = fieldContainer.querySelector('.error');
64
+ if (existingErrorMessageElement) {
65
+ (_a = existingErrorMessageElement === null || existingErrorMessageElement === void 0 ? void 0 : existingErrorMessageElement.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(existingErrorMessageElement);
66
+ }
67
+ }
68
+ showErrorForInvalidField(field) {
69
+ field.insertAdjacentHTML('afterend', this.buildFieldErrorHtml(field));
70
+ }
71
+ buildFieldErrorHtml(field) {
72
+ const data = html `<p class="error">${field.validationMessage}</p>`;
73
+ return this.getRenderString(data);
74
+ }
75
+ get formFields() {
76
+ return Array.from(this.element.children).filter(node => {
77
+ const data = node.attributes.getNamedItem('data-ariadne-form-field');
78
+ if ((data === null || data === void 0 ? void 0 : data.value) === 'true')
79
+ return true;
80
+ });
81
+ }
82
+ get firstInvalidField() {
83
+ return this.formFields.find(field => !field.checkValidity());
84
+ }
85
+ }
@@ -0,0 +1,22 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ import type { TemplateResult } from 'lit-html';
3
+ declare type HTMLFormField = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
4
+ export default class AriadneFormWith extends Controller {
5
+ static targets: string[];
6
+ readonly formFieldTargets: [HTMLFormField];
7
+ connect(): void;
8
+ disconnect(): void;
9
+ onBlur: (event: Event) => void;
10
+ onSubmit: (event: Event) => void;
11
+ validateForm(): boolean;
12
+ validateField(field: HTMLFormField): boolean;
13
+ shouldValidateField(field: HTMLFormField): boolean;
14
+ refreshErrorForInvalidField(field: HTMLFormField, isValid: boolean): void;
15
+ removeExistingErrorMessage(field: HTMLFormField): void;
16
+ showErrorForInvalidField(field: HTMLFormField): void;
17
+ buildFieldErrorHtml(field: HTMLFormField): string;
18
+ get formFields(): HTMLFormField[];
19
+ get firstInvalidField(): HTMLFormField | undefined;
20
+ getRenderString: (data: TemplateResult) => string;
21
+ }
22
+ export {};
@@ -0,0 +1,84 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ import { html } from 'lit-html';
3
+ export default class AriadneFormWith extends Controller {
4
+ constructor() {
5
+ super(...arguments);
6
+ this.onBlur = (event) => {
7
+ this.validateField(event.target);
8
+ };
9
+ this.onSubmit = (event) => {
10
+ var _a;
11
+ if (!this.validateForm()) {
12
+ event.preventDefault();
13
+ (_a = this.firstInvalidField) === null || _a === void 0 ? void 0 : _a.focus();
14
+ }
15
+ };
16
+ this.getRenderString = (data) => {
17
+ const { strings, values } = data;
18
+ const v = [...values, ''].map(e => (typeof e === 'object' ? this.getRenderString(e) : e));
19
+ return strings.reduce((acc, s, i) => acc + s + v[i], '');
20
+ };
21
+ }
22
+ connect() {
23
+ this.element.setAttribute('novalidate', 'true');
24
+ this.element.addEventListener('blur', this.onBlur, true);
25
+ this.element.addEventListener('submit', this.onSubmit);
26
+ this.element.addEventListener('ajax:beforeSend', this.onSubmit);
27
+ }
28
+ disconnect() {
29
+ this.element.removeEventListener('blur', this.onBlur);
30
+ this.element.removeEventListener('submit', this.onSubmit);
31
+ this.element.removeEventListener('ajax:beforeSend', this.onSubmit);
32
+ }
33
+ validateForm() {
34
+ let isValid = true;
35
+ // Not using `find` because we want to validate all the fields
36
+ for (const field of this.formFields) {
37
+ if (this.shouldValidateField(field) && !this.validateField(field))
38
+ isValid = false;
39
+ }
40
+ return isValid;
41
+ }
42
+ validateField(field) {
43
+ if (!this.shouldValidateField(field))
44
+ return true;
45
+ const isValid = field.checkValidity();
46
+ field.classList.toggle('invalid', !isValid);
47
+ this.refreshErrorForInvalidField(field, isValid);
48
+ return isValid;
49
+ }
50
+ shouldValidateField(field) {
51
+ return (!field.disabled &&
52
+ !field.classList.contains('ProseMirror') &&
53
+ !['file', 'reset', 'submit', 'button'].includes(field.type));
54
+ }
55
+ refreshErrorForInvalidField(field, isValid) {
56
+ this.removeExistingErrorMessage(field);
57
+ if (!isValid)
58
+ this.showErrorForInvalidField(field);
59
+ }
60
+ removeExistingErrorMessage(field) {
61
+ var _a;
62
+ const fieldContainer = field.closest('.field');
63
+ if (!fieldContainer)
64
+ return;
65
+ const existingErrorMessageElement = fieldContainer.querySelector('.error');
66
+ if (existingErrorMessageElement) {
67
+ (_a = existingErrorMessageElement === null || existingErrorMessageElement === void 0 ? void 0 : existingErrorMessageElement.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(existingErrorMessageElement);
68
+ }
69
+ }
70
+ showErrorForInvalidField(field) {
71
+ field.insertAdjacentHTML('afterend', this.buildFieldErrorHtml(field));
72
+ }
73
+ buildFieldErrorHtml(field) {
74
+ const data = html `<p class="error">${field.validationMessage}</p>`;
75
+ return this.getRenderString(data);
76
+ }
77
+ get formFields() {
78
+ return Array.from(this.formFieldTargets);
79
+ }
80
+ get firstInvalidField() {
81
+ return this.formFields.find(field => !field.checkValidity());
82
+ }
83
+ }
84
+ AriadneFormWith.targets = ['formField'];
@@ -0,0 +1,2 @@
1
+ import './tab-container-component';
2
+ import './time-ago-component';
@@ -0,0 +1,16 @@
1
+ import { Application } from '@hotwired/stimulus';
2
+ import AriadneForm from './ariadne-form';
3
+ import ClipboardCopyComponent from './clipboard-copy-component';
4
+ import RichTextAreaComponent from './rich-text-area-component';
5
+ import SlideoverComponent from './slideover-component';
6
+ import TabNavComponent from './tab-nav-component';
7
+ import TooltipComponent from './tooltip-component';
8
+ import './tab-container-component';
9
+ import './time-ago-component';
10
+ const application = Application.start();
11
+ application.register('clipboard-copy-component', ClipboardCopyComponent);
12
+ application.register('ariadne-form', AriadneForm);
13
+ application.register('rich-text-area-component', RichTextAreaComponent);
14
+ application.register('slideover-component', SlideoverComponent);
15
+ application.register('tab-nav-component', TabNavComponent);
16
+ application.register('tooltip-component', TooltipComponent);
@@ -19,8 +19,8 @@ module Ariadne
19
19
  }.freeze
20
20
  VALID_SIZES = SIZE_CLASS_MAPPINGS.keys.freeze
21
21
 
22
- DEFAULT_CLASSES = "ariadne-inline-flex ariadne-items-center ariadne-border ariadne-shadow-sm focus:ariadne-outline-none focus:ariadne-ring-2 focus:ariadne-ring-offset-2"
23
- DEFAULT_NUDE_CLASSES = "ariadne-inline-flex focus:ariadne-outline-none focus:ariadne-ring-2 focus:ariadne-ring-offset-2"
22
+ DEFAULT_CLASSES = "ariadne-items-center ariadne-border ariadne-shadow-sm focus:ariadne-outline-none focus:ariadne-ring-2 focus:ariadne-ring-offset-2"
23
+ DEFAULT_NUDE_CLASSES = "focus:ariadne-outline-none focus:ariadne-ring-2 focus:ariadne-ring-offset-2"
24
24
 
25
25
  DEFAULT_SIZE = :md
26
26
 
@@ -0,0 +1,4 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class ClipboardCopyComponent extends Controller {
3
+ copy(): void;
4
+ }
@@ -0,0 +1,18 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class ClipboardCopyComponent extends Controller {
3
+ copy() {
4
+ const value = this.element.attributes.getNamedItem('value');
5
+ const forNode = this.element.attributes.getNamedItem('for');
6
+ if (value) {
7
+ navigator.clipboard.writeText(value.value);
8
+ }
9
+ else if (forNode) {
10
+ const node = document.getElementById(forNode.value);
11
+ navigator.clipboard.writeText((node === null || node === void 0 ? void 0 : node.textContent) || '');
12
+ }
13
+ else {
14
+ // just copy inner text
15
+ navigator.clipboard.writeText(this.element.textContent || '');
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,4 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class ClipboardCopyComponent extends Controller {
3
+ copy(): void;
4
+ }
@@ -0,0 +1,18 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class ClipboardCopyComponent extends Controller {
3
+ copy() {
4
+ const value = this.element.attributes.getNamedItem('value');
5
+ const forNode = this.element.attributes.getNamedItem('for');
6
+ if (value) {
7
+ navigator.clipboard.writeText(value.value);
8
+ }
9
+ else if (forNode) {
10
+ const node = document.getElementById(forNode.value);
11
+ navigator.clipboard.writeText((node === null || node === void 0 ? void 0 : node.textContent) || '');
12
+ }
13
+ else {
14
+ // just copy inner text
15
+ navigator.clipboard.writeText(this.element.textContent || '');
16
+ }
17
+ }
18
+ }
@@ -4,7 +4,7 @@
4
4
  <% tab.text { @public_tab_text } %>
5
5
  <% tab.panel(attributes: {:"data-public" => true}) do %>
6
6
  <%= ariadne_form_with(url: @url, method: @method, classes: @classes, attributes: @attributes) do |comment_box| %>
7
- <div class="ariadne-overflow-hidden ariadne-border ariadne-border-gray-300 ariadne-shadow-sm focus-within:ariadne-border-indigo-500 focus-within:ariadne-ring-1 focus-within:ariadne-ring-indigo-500">
7
+ <div class="ariadne-overflow-hidden ariadne-border ariadne-border-gray-300 ariadne-shadow-sm">
8
8
  <%= hidden_field_tag 'message_public', true %>
9
9
  <%= render(Ariadne::RichTextAreaComponent.new(name: :public_bodytext, sr_label: "Select reply type", attributes: { required: true})) %>
10
10
  <% comment_box.submit { @submit } %>
@@ -19,7 +19,7 @@
19
19
  <% tab.text { @internal_tab_text } %>
20
20
  <% tab.panel do %>
21
21
  <%= ariadne_form_with(url: @url, method: @method, classes: @classes, attributes: @attributes) do |comment_box| %>
22
- <div class="ariadne-overflow-hidden ariadne-border ariadne-border-gray-300 ariadne-shadow-sm focus-within:ariadne-border-indigo-500 focus-within:ariadne-ring-1 focus-within:ariadne-ring-indigo-500">
22
+ <div class="ariadne-overflow-hidden ariadne-border ariadne-border-gray-300 ariadne-shadow-sm">
23
23
  <%= hidden_field_tag 'message_public', false %>
24
24
  <%= render(Ariadne::RichTextAreaComponent.new(name: :internal_bodytext, sr_label: "Select reply type", attributes: { required: true})) %>
25
25
  <% comment_box.submit { @submit } %>
@@ -19,6 +19,10 @@ module Ariadne
19
19
  BASE_WRAPPER_CLASSES = "ariadne-flex ariadne-flex-col ariadne-h-screen ariadne-justify-between"
20
20
  BASE_MAIN_CLASSES = "ariadne-flex-auto"
21
21
 
22
+ # this is defined here for the Tailwind parser to pick up; it can be useful
23
+ # in situations where hiddenness is defined by a kwarg, eg `selected: false`
24
+ BASE_HIDDEN_CLASS = "ariadne-hidden"
25
+
22
26
  INVALID_ARIA_LABEL_TAGS = [:div, :span, :p].freeze
23
27
 
24
28
  private def raise_on_invalid_options?
@@ -26,7 +26,7 @@ module Ariadne
26
26
 
27
27
  DEFAULT_TEXT_OPEN_CLASSES = "ariadne-text-state-open"
28
28
  DEFAULT_TEXT_CLOSED_CLASSES = "ariadne-text-state-closed"
29
- DEFAULT_TEXT_CLASSES = "ariadne-pl-2 ariadne-text-sm ariadne-font-medium ariadne-text-gray-900"
29
+ DEFAULT_TEXT_CLASSES = "ariadne-pl-2 ariadne-text-sm ariadne-font-medium"
30
30
  renders_one :icon, lambda { |tag: :svg, icon:, variant:, size: Ariadne::HeroiconComponent::SIZE_DEFAULT, classes: "", attributes: {}, text_classes: "", text_attributes: {}|
31
31
  actual_text_classes = class_names(DEFAULT_TEXT_CLASSES, text_classes)
32
32
  Ariadne::HeroiconComponent.new(tag: tag, icon: icon, variant: variant, size: size, classes: classes, attributes: attributes, text_classes: actual_text_classes, text_attributes: text_attributes) { content }
@@ -36,7 +36,7 @@ module Ariadne
36
36
  Ariadne::BaseComponent.new(tag: :span, classes: classes, attributes: attributes) { content }
37
37
  }
38
38
 
39
- DEFAULT_LABEL_CLASSES = "ariadne-pl-2 ariadne-text-sm ariadne-font-medium ariadne-text-gray-900"
39
+ DEFAULT_LABEL_CLASSES = "ariadne-pl-2 ariadne-text-sm ariadne-font-medium"
40
40
  renders_one :text, lambda { |classes: "", attributes: {}|
41
41
  actual_classes = class_names(DEFAULT_LABEL_CLASSES, classes)
42
42
  Ariadne::BaseComponent.new(tag: :span, classes: actual_classes, attributes: attributes) { content }
@@ -5,7 +5,7 @@
5
5
  <span class="ariadne-px-6 ariadne-py-4 ariadne-flex ariadne-items-center ariadne-text-sm ariadne-font-medium">
6
6
  <%= panel.icon %>
7
7
  <span class="ariadne-ml-4 ariadne-text-sm ariadne-font-medium ariadne-text-gray-900"><%= panel.label %></span>
8
- <!-- Arrow separator for lg screens and up -->
8
+ <!-- TODO: fix this -->
9
9
  <% if idx + 1 < panels.size %>
10
10
  <div class="md:ariadne-block ariadne-hidden ariadne-absolute ariadne-top-0 ariadne-right-0 ariadne-h-full ariadne-w-5" aria-hidden="true">
11
11
  <svg class="ariadne-h-full ariadne-w-full ariadne-text-gray-300" viewBox="0 0 22 80" fill="none" preserveAspectRatio="none">
@@ -40,6 +40,7 @@ module Ariadne
40
40
  DEFAULT_ITEM_CLASSES = "ariadne-relative md:ariadne-flex-1 md:ariadne-flex"
41
41
  DEFAULT_WRAPPER_CLASSES = "group ariadne-flex ariadne-items-center ariadne-w-full"
42
42
 
43
+ # TODO: fix this
43
44
  renders_one :icon, lambda { |static_content = nil, &block|
44
45
  next static_content if static_content.present?
45
46
 
@@ -0,0 +1,6 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class RichTextArea extends Controller {
3
+ static targets: string[];
4
+ readonly editorTargets: [HTMLDivElement];
5
+ connect(): void;
6
+ }
@@ -0,0 +1,36 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ import { Editor } from '@tiptap/core';
3
+ import { Document } from '@tiptap/extension-document';
4
+ import { Paragraph } from '@tiptap/extension-paragraph';
5
+ import { Text } from '@tiptap/extension-text';
6
+ import DropCursor from '@tiptap/extension-dropcursor';
7
+ import GapCursor from '@tiptap/extension-gapcursor';
8
+ import { History } from '@tiptap/extension-history';
9
+ export default class RichTextArea extends Controller {
10
+ connect() {
11
+ for (const editorElement of this.editorTargets) {
12
+ const pmEditor = new Editor({
13
+ extensions: [DropCursor, GapCursor, History, Document, Paragraph, Text],
14
+ content: '',
15
+ injectCSS: false,
16
+ element: editorElement,
17
+ editorProps: {
18
+ attributes: {
19
+ class: 'ariadne-p-3'
20
+ }
21
+ },
22
+ parseOptions: {
23
+ preserveWhitespace: true
24
+ }
25
+ });
26
+ const tiptapValueContainer = editorElement.previousElementSibling;
27
+ if (tiptapValueContainer) {
28
+ const parentForm = editorElement.closest('form');
29
+ parentForm === null || parentForm === void 0 ? void 0 : parentForm.addEventListener('submit', () => {
30
+ tiptapValueContainer.setAttribute('value', pmEditor.getText() || '');
31
+ });
32
+ }
33
+ }
34
+ }
35
+ }
36
+ RichTextArea.targets = ['editor'];
@@ -1,21 +1,34 @@
1
1
  import {Controller} from '@hotwired/stimulus'
2
2
 
3
3
  import {Editor} from '@tiptap/core'
4
- import {StarterKit} from '@tiptap/starter-kit'
4
+
5
+ import {Document} from '@tiptap/extension-document'
6
+ import {Paragraph} from '@tiptap/extension-paragraph'
7
+ import {Text} from '@tiptap/extension-text'
8
+
9
+ import DropCursor from '@tiptap/extension-dropcursor'
10
+ import GapCursor from '@tiptap/extension-gapcursor'
11
+ import {History} from '@tiptap/extension-history'
5
12
 
6
13
  export default class RichTextArea extends Controller {
14
+ static targets = ['editor']
15
+
16
+ declare readonly editorTargets: [HTMLDivElement]
17
+
7
18
  connect() {
8
- const editorElements = document.getElementsByClassName('tiptap-editor')
9
- for (const editorElement of editorElements) {
10
- new Editor({
11
- element: editorElement,
12
- extensions: [StarterKit],
19
+ for (const editorElement of this.editorTargets) {
20
+ const pmEditor = new Editor({
21
+ extensions: [DropCursor, GapCursor, History, Document, Paragraph, Text],
13
22
  content: '',
23
+ injectCSS: false,
24
+ element: editorElement,
14
25
  editorProps: {
15
26
  attributes: {
16
- class:
17
- 'focus:ariadne-outline-none ariadne-block ariadne-w-full ariadne-resize-none ariadne-p-0 ariadne-pb-2 ariadne-border-none focus:ariadne-ring-0 sm:ariadne-text-sm'
27
+ class: 'ariadne-p-3'
18
28
  }
29
+ },
30
+ parseOptions: {
31
+ preserveWhitespace: true
19
32
  }
20
33
  })
21
34
 
@@ -24,7 +37,7 @@ export default class RichTextArea extends Controller {
24
37
  const parentForm = editorElement.closest('form')
25
38
 
26
39
  parentForm?.addEventListener('submit', () => {
27
- tiptapValueContainer.setAttribute('value', editorElement.textContent || '')
40
+ tiptapValueContainer.setAttribute('value', pmEditor.getText() || '')
28
41
  })
29
42
  }
30
43
  }
@@ -2,5 +2,5 @@
2
2
  <% if @has_form %>
3
3
  <input type="hidden" data-tiptap-value-container=true name="<%= @name %>" id="<%= @name %>">
4
4
  <% end %>
5
- <div class="tiptap-editor"></div>
5
+ <div class="tiptap-editor" data-rich-text-area-component-target="editor"></div>
6
6
  <% end %>
@@ -0,0 +1,9 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class SlideoverComponent extends Controller {
3
+ static targets: string[];
4
+ readonly expandableTarget: HTMLDivElement;
5
+ readonly expandWrapperTarget: HTMLDivElement;
6
+ readonly slidePanelTargets: [HTMLDivElement];
7
+ readonly buttonWrapperTarget: HTMLDivElement;
8
+ toggle(): void;
9
+ }
@@ -0,0 +1,10 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class SlideoverComponent extends Controller {
3
+ toggle() {
4
+ this.expandableTarget.classList.toggle('ariadne-hidden');
5
+ for (const slidePanel of this.slidePanelTargets) {
6
+ slidePanel.classList.toggle('ariadne-hidden');
7
+ }
8
+ }
9
+ }
10
+ SlideoverComponent.targets = ['expandable', 'expandWrapper', 'slidePanel', 'buttonWrapper'];
@@ -10,17 +10,8 @@ export default class SlideoverComponent extends Controller {
10
10
 
11
11
  toggle() {
12
12
  this.expandableTarget.classList.toggle('ariadne-hidden')
13
- this.expandWrapperTarget.classList.toggle('bg-filter-panel')
14
13
  for (const slidePanel of this.slidePanelTargets) {
15
14
  slidePanel.classList.toggle('ariadne-hidden')
16
15
  }
17
- this.buttonWrapperTarget.classList.toggle('bg-filter-panel')
18
- if (document.getElementById('btnClose')?.classList.contains('ariadne-hidden')) {
19
- const formID = this.buttonWrapperTarget.getAttribute('data-slideover-component-form-id')
20
- if (formID) {
21
- const form = <HTMLFormElement>document.getElementById(formID)
22
- form?.submit()
23
- }
24
- }
25
16
  }
26
17
  }
@@ -0,0 +1,9 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class SlideoverComponent extends Controller {
3
+ static targets: string[];
4
+ readonly expandableTarget: HTMLDivElement;
5
+ readonly expandWrapperTarget: HTMLDivElement;
6
+ readonly slidePanelTargets: [HTMLDivElement];
7
+ readonly buttonWrapperTarget: HTMLDivElement;
8
+ toggle(): void;
9
+ }
@@ -1,11 +1,9 @@
1
1
  <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |slideover| %>
2
- <div data-slideover-component-target="expandWrapper" class="ariadne-flex ariadne-flex-col ariadne-z-10">
3
- <div data-slideover-component-target="expandable" class="ariadne-hidden ariadne-px-3 ariadne-pb-4">
4
- <%= content %>
5
- </div>
6
- <div data-slideover-component-target="buttonWrapper" data-slideover-component-form-id="<%= @form_id %>" class="ariadne-relative ariadne-flex ariadne-justify-center">
7
- <%= open_button %>
8
- <%= close_button %>
9
- </div>
2
+ <div data-slideover-component-target="expandable" class="ariadne-hidden ariadne-px-3">
3
+ <%= content %>
4
+ </div>
5
+ <div data-slideover-component-target="buttonWrapper" class="ariadne-relative ariadne-flex ariadne-justify-center">
6
+ <%= open_button %>
7
+ <%= close_button %>
10
8
  </div>
11
9
  <% end %>
@@ -0,0 +1,19 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class SlideoverComponent extends Controller {
3
+ toggle() {
4
+ var _a;
5
+ // eslint-disable-next-line no-debugger
6
+ debugger;
7
+ this.expandableTarget.classList.toggle('hidden');
8
+ this.expandWrapperTarget.classList.toggle('bg-filter-panel');
9
+ for (const slidePanel of this.slidePanelTargets) {
10
+ slidePanel.classList.toggle('hidden');
11
+ }
12
+ this.buttonWrapperTarget.classList.toggle('bg-filter-panel');
13
+ if ((_a = document.getElementById('btnClose')) === null || _a === void 0 ? void 0 : _a.classList.contains('hidden')) {
14
+ const form = this.buttonWrapperTarget.closest('form');
15
+ form === null || form === void 0 ? void 0 : form.submit();
16
+ }
17
+ }
18
+ }
19
+ SlideoverComponent.targets = ['expandable', 'expandWrapper', 'slidePanel', 'buttonWrapper'];