ariadne_view_components 0.0.18 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
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'];