ariadne_view_components 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/assets/builds/ariadne_view_components.css +1874 -0
- data/app/assets/javascripts/ariadne.d.ts +1 -0
- data/app/assets/javascripts/ariadne_view_components.js +1 -1
- data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
- data/app/assets/javascripts/clipboard-copy-component.d.ts +4 -0
- data/app/assets/javascripts/slideover-component.d.ts +9 -0
- data/app/assets/javascripts/time_ago_component.d.ts +1 -0
- data/app/assets/javascripts/tooltip-component.d.ts +24 -0
- data/app/assets/stylesheets/application.ariadne_view_components.css +5 -3
- data/app/assets/stylesheets/tooltip-component.css +37 -0
- data/app/components/ariadne/ariadne.d.ts +1 -0
- data/app/components/ariadne/ariadne.js +9 -0
- data/app/components/ariadne/ariadne.ts +3 -0
- data/app/components/ariadne/base_button.rb +9 -8
- data/app/components/ariadne/blankslate_component.rb +1 -1
- data/app/components/ariadne/body_component.rb +30 -0
- data/app/components/ariadne/button_component.rb +5 -10
- data/app/components/ariadne/clipboard-copy-component.d.ts +4 -0
- data/app/components/ariadne/clipboard-copy-component.js +18 -0
- data/app/components/ariadne/clipboard_copy_component.d.ts +4 -0
- data/app/components/ariadne/clipboard_copy_component.html.erb +2 -2
- data/app/components/ariadne/clipboard_copy_component.js +18 -0
- data/app/components/ariadne/clipboard_copy_component.rb +41 -3
- data/app/components/ariadne/comment_component.html.erb +25 -0
- data/app/components/ariadne/comment_component.rb +45 -0
- data/app/components/ariadne/component.rb +2 -1
- data/app/components/ariadne/container_component.rb +1 -1
- data/app/components/ariadne/flash_component.rb +1 -1
- data/app/components/ariadne/flex_component.rb +51 -0
- data/app/components/ariadne/grid_component.html.erb +12 -3
- data/app/components/ariadne/grid_component.rb +18 -7
- data/app/components/ariadne/header_component.rb +1 -1
- data/app/components/ariadne/heading_component.rb +2 -2
- data/app/components/ariadne/heroicon_component.html.erb +4 -6
- data/app/components/ariadne/heroicon_component.rb +18 -7
- data/app/components/ariadne/inline_flex_component.rb +11 -9
- data/app/components/ariadne/link_component.rb +13 -8
- data/app/components/ariadne/list_component.html.erb +5 -7
- data/app/components/ariadne/list_component.rb +4 -34
- data/app/components/ariadne/main_component.rb +32 -0
- data/app/components/ariadne/slideover-component.d.ts +9 -0
- data/app/components/ariadne/slideover-component.js +20 -0
- data/app/components/ariadne/slideover_component.d.ts +9 -0
- data/app/components/ariadne/slideover_component.html.erb +1 -4
- data/app/components/ariadne/slideover_component.js +19 -0
- data/app/components/ariadne/slideover_component.rb +19 -15
- data/app/components/ariadne/time_ago_component.d.ts +1 -0
- data/app/components/ariadne/time_ago_component.js +1 -0
- data/app/components/ariadne/tooltip-component.d.ts +24 -0
- data/app/components/ariadne/tooltip-component.js +42 -0
- data/app/components/ariadne/tooltip-component.ts +57 -0
- data/app/components/ariadne/tooltip_component.html.erb +4 -0
- data/app/components/ariadne/tooltip_component.rb +34 -31
- data/app/lib/ariadne/form_builder.rb +14 -14
- data/lib/ariadne/classify.rb +4 -98
- data/lib/ariadne/view_components/version.rb +1 -1
- data/lib/ariadne/view_components.rb +31 -29
- data/lib/rubocop/cop/ariadne/ariadne_heroicon.rb +2 -2
- data/lib/tasks/docs.rake +4 -0
- data/static/arguments.yml +89 -13
- data/static/audited_at.json +4 -0
- data/static/classes.yml +40 -8
- data/static/constants.json +83 -101
- data/static/statuses.json +4 -0
- metadata +48 -6
@@ -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 @@
|
|
1
|
+
import '@github/time-elements';
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus';
|
2
|
+
import type { Instance, Placement } from '@popperjs/core';
|
3
|
+
export default class TooltipComponent extends Controller {
|
4
|
+
static targets: string[];
|
5
|
+
readonly triggerTarget: HTMLElement;
|
6
|
+
readonly tooltipTarget: HTMLElement;
|
7
|
+
static values: {
|
8
|
+
placement: {
|
9
|
+
type: StringConstructor;
|
10
|
+
default: string;
|
11
|
+
};
|
12
|
+
offset: {
|
13
|
+
type: ArrayConstructor;
|
14
|
+
default: number[];
|
15
|
+
};
|
16
|
+
};
|
17
|
+
readonly placementValue: Placement;
|
18
|
+
readonly offsetValue: Array<number>;
|
19
|
+
popperInstance: Instance;
|
20
|
+
connect(): void;
|
21
|
+
disconnect(): void;
|
22
|
+
show(): void;
|
23
|
+
hide(): void;
|
24
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
.tooltip-arrow,
|
2
|
+
.tooltip-arrow::before {
|
3
|
+
position: absolute;
|
4
|
+
width: 8px;
|
5
|
+
height: 8px;
|
6
|
+
background: inherit;
|
7
|
+
}
|
8
|
+
|
9
|
+
.tooltip-arrow {
|
10
|
+
visibility: hidden;
|
11
|
+
}
|
12
|
+
|
13
|
+
tooltip[data-tooltip-show] .tooltip-arrow::before {
|
14
|
+
visibility: visible;
|
15
|
+
content: '';
|
16
|
+
transform: rotate(45deg);
|
17
|
+
}
|
18
|
+
|
19
|
+
tooltip[data-popper-placement^='top'][data-tooltip-show] > .tooltip-arrow {
|
20
|
+
bottom: -4px;
|
21
|
+
}
|
22
|
+
|
23
|
+
tooltip[data-popper-placement^='bottom'] > .tooltip-arrow {
|
24
|
+
top: -4px;
|
25
|
+
}
|
26
|
+
|
27
|
+
tooltip[data-popper-placement^='left'] > .tooltip-arrow {
|
28
|
+
right: -4px;
|
29
|
+
}
|
30
|
+
|
31
|
+
tooltip[data-popper-placement^='right'] > .tooltip-arrow {
|
32
|
+
left: -4px;
|
33
|
+
}
|
34
|
+
|
35
|
+
tooltip[data-tooltip-show] {
|
36
|
+
display: block;
|
37
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
import './time_ago_component';
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { Application } from '@hotwired/stimulus';
|
2
|
+
import ClipboardCopyComponent from './clipboard-copy-component';
|
3
|
+
import SlideoverComponent from './slideover-component';
|
4
|
+
import TooltipComponent from './tooltip-component';
|
5
|
+
import './time_ago_component';
|
6
|
+
const application = Application.start();
|
7
|
+
application.register('clipboard-copy-component', ClipboardCopyComponent);
|
8
|
+
application.register('slideover-component', SlideoverComponent);
|
9
|
+
application.register('tooltip-component', TooltipComponent);
|
@@ -2,9 +2,12 @@ import {Application} from '@hotwired/stimulus'
|
|
2
2
|
|
3
3
|
import ClipboardCopyComponent from './clipboard-copy-component'
|
4
4
|
import SlideoverComponent from './slideover-component'
|
5
|
+
import TooltipComponent from './tooltip-component'
|
5
6
|
|
6
7
|
import './time_ago_component'
|
7
8
|
|
8
9
|
const application = Application.start()
|
10
|
+
|
9
11
|
application.register('clipboard-copy-component', ClipboardCopyComponent)
|
10
12
|
application.register('slideover-component', SlideoverComponent)
|
13
|
+
application.register('tooltip-component', TooltipComponent)
|
@@ -7,27 +7,28 @@ module Ariadne
|
|
7
7
|
TAG_OPTIONS = [DEFAULT_TAG, :a, :summary].freeze
|
8
8
|
|
9
9
|
DEFAULT_TYPE = :button
|
10
|
-
|
10
|
+
TYPE_SUBMIT = :submit
|
11
|
+
TYPE_OPTIONS = [DEFAULT_TYPE, :reset, TYPE_SUBMIT].freeze
|
11
12
|
|
12
13
|
# TODO: dedupe the classes
|
13
14
|
SIZE_CLASS_MAPPINGS = {
|
14
15
|
xs: "inline-flex items-center px-2.5 py-1.5 text-xs font-medium rounded",
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
sm: "inline-flex items-center px-3 py-2 text-sm leading-4 font-medium rounded-m",
|
17
|
+
md: "inline-flex items-center px-4 py-2 text-sm font-medium rounded-md",
|
18
|
+
lg: "inline-flex items-center px-4 py-2 text-base font-medium rounded-md",
|
18
19
|
xl: "inline-flex items-center px-6 py-3 text-base font-medium rounded-md",
|
19
20
|
}.freeze
|
20
21
|
VALID_SIZES = SIZE_CLASS_MAPPINGS.keys.freeze
|
21
22
|
|
22
23
|
DEFAULT_CLASSES = "inline-flex items-center px-4 py-2 text-sm border border-gray-300 shadow-sm text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
23
24
|
|
24
|
-
DEFAULT_SIZE = :
|
25
|
+
DEFAULT_SIZE = :md
|
25
26
|
|
26
27
|
# @example Setting the size
|
27
28
|
# <%= render(Ariadne::BaseButton.new(size: :xs)) { "I am an extra small button!" } %>
|
28
|
-
# <%= render(Ariadne::BaseButton.new(size: :
|
29
|
-
# <%= render(Ariadne::BaseButton.new(size: :
|
30
|
-
# <%= render(Ariadne::BaseButton.new(size: :
|
29
|
+
# <%= render(Ariadne::BaseButton.new(size: :sm)) { "I am a small button!" } %>
|
30
|
+
# <%= render(Ariadne::BaseButton.new(size: :md)) { "I am a medium button!" } %>
|
31
|
+
# <%= render(Ariadne::BaseButton.new(size: :lg)) { "I am a large button!" } %>
|
31
32
|
# <%= render(Ariadne::BaseButton.new(size: :xl)) { "I am an extra large button!" } %>
|
32
33
|
#
|
33
34
|
# @param tag [Symbol] <%= one_of(Ariadne::BaseButton::TAG_OPTIONS) %>
|
@@ -79,7 +79,7 @@ module Ariadne
|
|
79
79
|
# @param href [String] URL to be used for the primary action.
|
80
80
|
# @param classes [String] <%= link_to_classes_docs %>
|
81
81
|
# @param attributes [Hash] Same arguments as <%= link_to_component(Ariadne::HeroiconComponent) %>.
|
82
|
-
renders_one :primary_action, lambda { |href: nil, tag: :a, method: nil, size: :
|
82
|
+
renders_one :primary_action, lambda { |href: nil, tag: :a, method: nil, size: :md, scheme: :default, classes: "", attributes: {}|
|
83
83
|
attributes[:href] = href
|
84
84
|
attributes[:method] = method
|
85
85
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# Add a general description of component here
|
5
|
+
# Add additional usage considerations or best practices that may aid the user to use the component correctly.
|
6
|
+
# @accessibility Add any accessibility considerations
|
7
|
+
class BodyComponent < Ariadne::Component
|
8
|
+
DEFAULT_CLASSES = "flex flex-col min-h-screen"
|
9
|
+
|
10
|
+
# @example Default
|
11
|
+
#
|
12
|
+
# <%= render(Ariadne::BodyComponent.new) { "Example" } %>
|
13
|
+
#
|
14
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
15
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
16
|
+
def initialize(classes: "", attributes: {})
|
17
|
+
@tag = :body
|
18
|
+
@classes = class_names(
|
19
|
+
DEFAULT_CLASSES,
|
20
|
+
classes
|
21
|
+
)
|
22
|
+
|
23
|
+
@attributes = attributes
|
24
|
+
end
|
25
|
+
|
26
|
+
def call
|
27
|
+
render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) { content }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -58,18 +58,13 @@ module Ariadne
|
|
58
58
|
#
|
59
59
|
# @param tag [Symbol, String] The rendered tag name
|
60
60
|
# @param text [String] The text content of the tooltip. This should be brief and no longer than a sentence.
|
61
|
-
# @param direction [Symbol] <%= one_of(Ariadne::TooltipComponent::
|
61
|
+
# @param direction [Symbol] <%= one_of(Ariadne::TooltipComponent::VALID_PLACEMENTS) %>
|
62
62
|
# @param classes [String] <%= link_to_classes_docs %>
|
63
63
|
# @param attributes [Hash] Same arguments as <%= link_to_component(Ariadne::TooltipComponent) %>.
|
64
|
-
renders_one :tooltip, lambda { |tag:
|
64
|
+
renders_one :tooltip, lambda { |tag: Ariadne::TooltipComponent::DEFAULT_TAG, text:, direction: Ariadne::TooltipComponent::DEFAULT_PLACEMENT, type: Ariadne::TooltipComponent::TYPE_DEFAULT, classes: "", attributes: {}|
|
65
65
|
raise ArgumentError, "Buttons with a tooltip must have a unique `id` set on the `Button`." if @id.blank?
|
66
66
|
|
67
|
-
|
68
|
-
tag = check_incoming_tag(:"tool-tip", tag)
|
69
|
-
attributes[:for] = @id
|
70
|
-
attributes[:type] = check_incoming_attribute(:description, attributes[:type])
|
71
|
-
|
72
|
-
Ariadne::TooltipComponent.new(tag: tag, text: text, direction: direction, type: type, classes: classes, attributes: attributes)
|
67
|
+
Ariadne::TooltipComponent.new(for_id: @id, tag: tag, text: text, direction: direction, type: type, classes: classes, attributes: attributes)
|
73
68
|
}
|
74
69
|
|
75
70
|
# @example Schemes
|
@@ -81,8 +76,8 @@ module Ariadne
|
|
81
76
|
# <%= render(Ariadne::ButtonComponent.new(scheme: :danger)) { "Danger" } %>
|
82
77
|
#
|
83
78
|
# @example Sizes
|
84
|
-
# <%= render(Ariadne::ButtonComponent.new(size: :
|
85
|
-
# <%= render(Ariadne::ButtonComponent.new(size: :
|
79
|
+
# <%= render(Ariadne::ButtonComponent.new(size: :sm)) { "Small" } %>
|
80
|
+
# <%= render(Ariadne::ButtonComponent.new(size: :md)) { "Medium" } %>
|
86
81
|
#
|
87
82
|
# @example With leading visual
|
88
83
|
# <%= render(Ariadne::ButtonComponent.new) do |c| %>
|
@@ -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
|
+
}
|
@@ -1,6 +1,6 @@
|
|
1
|
-
<%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes.merge(
|
1
|
+
<%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes.merge(controller_data)) do %>
|
2
2
|
<% if content.present? %>
|
3
|
-
<%= content %>
|
3
|
+
<%= content.to_s + tooltip.to_s %>
|
4
4
|
<% else %>
|
5
5
|
<%= render Ariadne::HeroiconComponent.new(icon: :duplicate, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE) %>
|
6
6
|
<%= render Ariadne::HeroiconComponent.new(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, attributes: { color: :success, style: "display: none;" }) %>
|
@@ -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
|
+
}
|
@@ -8,11 +8,28 @@ module Ariadne
|
|
8
8
|
class ClipboardCopyComponent < Ariadne::Component
|
9
9
|
DEFAULT_TAG = :"clipboard-copy"
|
10
10
|
|
11
|
-
DEFAULT_CLASSES =
|
11
|
+
DEFAULT_CLASSES = LinkComponent::DEFAULT_ACTIONABLE_CLASSES
|
12
12
|
|
13
13
|
DATA_CONTROLLER = "clipboard-copy-component"
|
14
14
|
DATA_ACTION = "click->clipboard-copy-component#copy"
|
15
15
|
|
16
|
+
# `Tooltip` that appears on mouse hover or keyboard focus over the button. Use tooltips sparingly and as a last resort.
|
17
|
+
# **Important:** This tooltip defaults to `type: :description`. In a few scenarios, `type: :label` may be more appropriate.
|
18
|
+
# Consult the <%= link_to_component(Ariadne::TooltipComponent) %> documentation for more information.
|
19
|
+
#
|
20
|
+
# @param tag [Symbol, String] The rendered tag name
|
21
|
+
# @param text [String] The text content of the tooltip. This should be brief and no longer than a sentence.
|
22
|
+
# @param direction [Symbol] <%= one_of(Ariadne::TooltipComponent::VALID_PLACEMENTS) %>
|
23
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
24
|
+
# @param attributes [Hash] Same arguments as <%= link_to_component(Ariadne::TooltipComponent) %>.
|
25
|
+
renders_one :tooltip, lambda { |tag: Ariadne::TooltipComponent::DEFAULT_TAG, text:, direction: Ariadne::TooltipComponent::DEFAULT_PLACEMENT, type: Ariadne::TooltipComponent::TYPE_DEFAULT, classes: "", attributes: {}|
|
26
|
+
raise ArgumentError, "CopyClipboardComponents with a tooltip must have a unique `id` set on the `CopyClipboardComponent`." if @id.blank?
|
27
|
+
|
28
|
+
@data_tooltip_direction = { "data-tooltip-component-direction": direction }
|
29
|
+
|
30
|
+
Ariadne::TooltipComponent.new(tag: tag, for_id: @id, text: text, direction: direction, type: type, classes: classes, attributes: attributes)
|
31
|
+
}
|
32
|
+
|
16
33
|
# @example Default
|
17
34
|
# <%= render(Ariadne::ClipboardCopyComponent.new(value: "Text to copy", aria_label: "Copy text to the system clipboard" )) %>
|
18
35
|
#
|
@@ -22,19 +39,22 @@ module Ariadne
|
|
22
39
|
# <% end %>
|
23
40
|
#
|
24
41
|
# @example Copying from an element
|
25
|
-
# <%= render(Ariadne::ClipboardCopyComponent.new(
|
42
|
+
# <%= render(Ariadne::ClipboardCopyComponent.new(for_id: "blob-path", aria_label: "Copy text to the system clipboard" )) %>
|
26
43
|
# <div id="blob-path">src/index.js</div>
|
27
44
|
#
|
28
45
|
# @param tag [Symbol, String] The rendered tag name
|
29
46
|
# @param classes [String] <%= link_to_classes_docs %>
|
30
47
|
# @param value [String] Text to copy into the users clipboard when they click the component.
|
48
|
+
# @param for_id [String] If `value` is not provided, the element with this id will be copied.
|
31
49
|
# @param aria_label [String] Text for accessibility. Can also be passed in as part of `attributes`, but it must be present.
|
32
50
|
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
33
|
-
def initialize(tag: DEFAULT_TAG, value: "", aria_label: "", classes: "", attributes: {})
|
51
|
+
def initialize(tag: DEFAULT_TAG, value: "", for_id: nil, aria_label: "", classes: "", attributes: {})
|
34
52
|
@attributes = attributes
|
35
53
|
@value = value
|
36
54
|
|
37
55
|
@attributes[:"aria-label"] = aria_label
|
56
|
+
@attributes[:for] ||= for_id
|
57
|
+
@id = @attributes[:id]
|
38
58
|
|
39
59
|
validate!
|
40
60
|
|
@@ -48,5 +68,23 @@ module Ariadne
|
|
48
68
|
raise ArgumentError, "Must provide either `value` or `for`" if @value.blank? && @attributes[:for].blank?
|
49
69
|
raise ArgumentError, "Must provide only `value` or `for`, not both" if @value.present? && @attributes[:for].present?
|
50
70
|
end
|
71
|
+
|
72
|
+
DATA_CONTROLLERS_WITH_TOOLTIPS = {
|
73
|
+
"data-controller": "#{DATA_CONTROLLER} #{Ariadne::TooltipComponent::DATA_CONTROLLER}",
|
74
|
+
"data-action": "#{DATA_ACTION} #{Ariadne::TooltipComponent::DATA_ACTION}",
|
75
|
+
"data-tooltip-component-target": "trigger",
|
76
|
+
}
|
77
|
+
|
78
|
+
DATA_CONTROLLERS =
|
79
|
+
{
|
80
|
+
"data-controller": DATA_CONTROLLER.to_s,
|
81
|
+
"data-action": DATA_ACTION,
|
82
|
+
}
|
83
|
+
|
84
|
+
def controller_data
|
85
|
+
return DATA_CONTROLLERS_WITH_TOOLTIPS if tooltip.present?
|
86
|
+
|
87
|
+
DATA_CONTROLLERS
|
88
|
+
end
|
51
89
|
end
|
52
90
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |comment| %>
|
2
|
+
<div>
|
3
|
+
<div class="flex items-center" aria-orientation="horizontal" role="tablist">
|
4
|
+
<% tabs.each do |tab| %>
|
5
|
+
<%= tab %>
|
6
|
+
<% end %>
|
7
|
+
</div>
|
8
|
+
<div class="mt-2">
|
9
|
+
<div id="tabs-1-panel-1" class="p-0.5 -m-0.5 rounded-lg" aria-labelledby="tabs-1-tab-1" role="tabpanel" tabindex="0">
|
10
|
+
<label for="comment" class="sr-only">Comment</label>
|
11
|
+
<div>
|
12
|
+
<textarea rows="5" name="comment" id="comment" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="Add your comment..."></textarea>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<div id="tabs-1-panel-2" class="p-0.5 -m-0.5 rounded-lg" aria-labelledby="tabs-1-tab-2" role="tabpanel" tabindex="0">
|
16
|
+
<div class="border-b">
|
17
|
+
<div class="mx-px mt-px px-3 pt-2 pb-12 text-sm leading-5 text-gray-800">Preview content will render here.</div>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
<div class="mt-2 flex justify-end">
|
23
|
+
<%= submit %>
|
24
|
+
</div>
|
25
|
+
<% end %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# Defines a submittble form for adding comments to a conversation.
|
5
|
+
class CommentComponent < Ariadne::Component
|
6
|
+
DEFAULT_TAG = :form
|
7
|
+
TAG_OPTIONS = [DEFAULT_TAG].freeze
|
8
|
+
|
9
|
+
DEFAULT_CLASSES = ""
|
10
|
+
|
11
|
+
DEFAULT_TAB_CLASSES = "text-gray-500 hover:text-gray-900 bg-white hover:bg-gray-100 px-3 py-1.5 border border-transparent text-sm font-medium rounded-md"
|
12
|
+
renders_many :tabs, lambda { |classes: "", attributes: {}|
|
13
|
+
actual_classes = class_names(DEFAULT_TAB_CLASSES, classes)
|
14
|
+
@tab_idx += 1
|
15
|
+
attributes[:id] = "comment-tabs-tab-#{@tab_idx}"
|
16
|
+
attributes[:"aria-controls"] = "comment-tabs-panel-#{@tab_idx}"
|
17
|
+
attributes[:role] = "tab"
|
18
|
+
attributes[:type] = "button"
|
19
|
+
|
20
|
+
Ariadne::BaseComponent.new(tag: :button, classes: actual_classes, attributes: attributes)
|
21
|
+
}
|
22
|
+
|
23
|
+
renders_one :submit, lambda { |classes: "", attributes: {}|
|
24
|
+
Ariadne::ButtonComponent.new(type: Ariadne::BaseButton::TYPE_SUBMIT, classes: classes, attributes: attributes)
|
25
|
+
}
|
26
|
+
|
27
|
+
# @example Default
|
28
|
+
#
|
29
|
+
# <%= render(Ariadne::CommentComponent.new(action: "#")) { "Example" } %>
|
30
|
+
#
|
31
|
+
# @param action [String] The action to take when the form is submitted.
|
32
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
33
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
34
|
+
def initialize(action:, classes: "", attributes: {})
|
35
|
+
@tag = DEFAULT_TAG
|
36
|
+
@classes = class_names(
|
37
|
+
DEFAULT_CLASSES,
|
38
|
+
classes
|
39
|
+
)
|
40
|
+
|
41
|
+
@tab_idx = 0
|
42
|
+
@attributes = attributes.merge(action: action)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -19,7 +19,8 @@ module Ariadne
|
|
19
19
|
include Ariadne::ActionViewExtensions::FormHelper
|
20
20
|
|
21
21
|
BASE_HTML_CLASSES = "h-full scroll-smooth bg-white antialiased"
|
22
|
-
BASE_BODY_CLASSES = "flex flex-col
|
22
|
+
BASE_BODY_CLASSES = "flex h-full flex-col"
|
23
|
+
BASE_WRAPPER_CLASSES = "flex flex-col h-screen justify-between"
|
23
24
|
BASE_MAIN_CLASSES = "flex-auto"
|
24
25
|
|
25
26
|
INVALID_ARIA_LABEL_TAGS = [:div, :span, :p].freeze
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Ariadne
|
4
4
|
# The container wraps the majority, if not all, of the content on a page.
|
5
5
|
class ContainerComponent < Ariadne::Component
|
6
|
-
DEFAULT_CLASSES = "px-4
|
6
|
+
DEFAULT_CLASSES = "px-4 sm:px-6 lg:px-8"
|
7
7
|
|
8
8
|
# @example Default
|
9
9
|
# <%= render(Ariadne::ContainerComponent.new) do |container| %>
|
@@ -84,7 +84,7 @@ module Ariadne
|
|
84
84
|
# @example With actions
|
85
85
|
# <%= render(Ariadne::FlashComponent.new) do |component| %>
|
86
86
|
# <% component.action do %>
|
87
|
-
# <%= render(Ariadne::ButtonComponent.new(size: :
|
87
|
+
# <%= render(Ariadne::ButtonComponent.new(size: :sm)) { "Take action" } %>
|
88
88
|
# <% end %>
|
89
89
|
# This is a flash message with actions!
|
90
90
|
# <% end %>
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# Add a general description of component here
|
5
|
+
# Add additional usage considerations or best practices that may aid the user to use the component correctly.
|
6
|
+
# @accessibility Add any accessibility considerations
|
7
|
+
class FlexComponent < Ariadne::Component
|
8
|
+
DEFAULT_TAG = :div
|
9
|
+
TAG_OPTIONS = [DEFAULT_TAG].freeze
|
10
|
+
|
11
|
+
DEFAULT_CLASSES = "flex"
|
12
|
+
|
13
|
+
VALID_TYPES = [:row, :column, :row_reverse, :column_reverse].freeze
|
14
|
+
|
15
|
+
# @example Default
|
16
|
+
#
|
17
|
+
# <%= render(Ariadne::FlexComponent.new(type: :column)) { "Example" } %>
|
18
|
+
#
|
19
|
+
# @param tag [Symbol, String] The rendered tag name.
|
20
|
+
# @param type [Symbol] <%= one_of(Ariadne::FlexComponent::VALID_TYPES) %>
|
21
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
22
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
23
|
+
def initialize(tag: DEFAULT_TAG, type:, classes: "", attributes: {})
|
24
|
+
@tag = check_incoming_tag(DEFAULT_TAG, tag)
|
25
|
+
@type = fetch_or_raise(VALID_TYPES, type)
|
26
|
+
|
27
|
+
flex_class = case @type
|
28
|
+
when :row
|
29
|
+
"flex-row"
|
30
|
+
when :column
|
31
|
+
"flex-col"
|
32
|
+
when :row_reverse
|
33
|
+
"flex-row-reverse"
|
34
|
+
when :column_reverse
|
35
|
+
"flex-col-reverse"
|
36
|
+
end
|
37
|
+
|
38
|
+
@classes = class_names(
|
39
|
+
DEFAULT_CLASSES,
|
40
|
+
classes,
|
41
|
+
flex_class
|
42
|
+
)
|
43
|
+
|
44
|
+
@attributes = attributes
|
45
|
+
end
|
46
|
+
|
47
|
+
def call
|
48
|
+
render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) { content }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,10 +1,19 @@
|
|
1
1
|
<%= render Ariadne::BaseComponent.new(tag: :ul, classes: @classes, attributes: @attributes) do |grid| %>
|
2
2
|
<% items.each do |item| %>
|
3
|
-
<li class="
|
3
|
+
<li class="<%= item.classes %> <%= item.has_href? ? Ariadne::GridComponent::DEFAULT_LINK_COLOR_CLASSES : "bg-white" %>">
|
4
4
|
<% if item.has_href? %>
|
5
5
|
<%= render Ariadne::LinkComponent.new(href: item.href) do %>
|
6
|
-
|
7
|
-
|
6
|
+
<%= item.entry %>
|
7
|
+
<% end %>
|
8
|
+
<% if item.actions.any? %>
|
9
|
+
<div>
|
10
|
+
<div class="-mt-px flex divide-x">
|
11
|
+
<% item.actions.each_with_index do |action, idx| %>
|
12
|
+
<div class="<%= idx.zero? ? '' : '-ml-px ' %>w-0 flex-1 flex">
|
13
|
+
<%= action %>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
16
|
+
</div>
|
8
17
|
</div>
|
9
18
|
<% end %>
|
10
19
|
<% else %>
|
@@ -3,9 +3,9 @@
|
|
3
3
|
module Ariadne
|
4
4
|
# Arranges items as a grid.
|
5
5
|
class GridComponent < Ariadne::Component
|
6
|
-
DEFAULT_CLASSES = "grid grid-cols-1 gap-6 sm:grid-cols-2
|
6
|
+
DEFAULT_CLASSES = "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3"
|
7
7
|
|
8
|
-
DEFAULT_LINK_COLOR_CLASSES = "text-button-text-color bg-button-bg-color
|
8
|
+
DEFAULT_LINK_COLOR_CLASSES = "text-button-text-color bg-button-bg-color focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500"
|
9
9
|
|
10
10
|
# The items to show in the grid.
|
11
11
|
renders_many :items, "Item"
|
@@ -29,17 +29,28 @@ module Ariadne
|
|
29
29
|
# This component is part of `GridComponent` and should not be
|
30
30
|
# used as a standalone component.
|
31
31
|
class Item < Ariadne::Component
|
32
|
-
|
33
|
-
next static_content if static_content.present?
|
32
|
+
DEFAULT_ITEM_CLASSES = "flex flex-col text-center rounded-lg shadow my-4 text-black-700 border-black"
|
34
33
|
|
35
|
-
|
34
|
+
DEFAULT_ENTRY_CLASSES = "group flex-1 flex flex-col p-8 hover:bg-button-hover-color hover:text-gray-500 rounded-lg"
|
35
|
+
renders_one :entry, lambda { |classes: "", &block|
|
36
|
+
view_context.capture do
|
37
|
+
render(Ariadne::BaseComponent.new(tag: :div, classes: classes)) { block&.call }
|
38
|
+
end
|
36
39
|
}
|
37
40
|
|
38
|
-
|
41
|
+
DEFAULT_ACTION_LINK_CLASSES = "text-button-text-color relative -mr-px w-0 flex-1 inline-flex items-center justify-center py-4 text-sm font-medium border border-transparent rounded-bl-lg rounded-lg"
|
42
|
+
renders_many :actions, lambda { |href:, icon:, label:, size: Ariadne::HeroiconComponent::SIZE_DEFAULT, variant: HeroiconsHelper::Icon::VARIANT_SOLID, classes: "", attributes: {}, text_classes: ""|
|
43
|
+
actual_classes = class_names(DEFAULT_ACTION_LINK_CLASSES, classes)
|
44
|
+
render(Ariadne::LinkComponent.new(href: href, classes: actual_classes, attributes: attributes)) do
|
45
|
+
render(Ariadne::HeroiconComponent.new(icon: icon, size: size, variant: variant, text_classes: text_classes)) { label }
|
46
|
+
end
|
47
|
+
}
|
48
|
+
|
49
|
+
attr_reader :href, :classes, :attributes
|
39
50
|
|
40
51
|
def initialize(href: nil, classes: "", attributes: {})
|
41
52
|
@href = href
|
42
|
-
@classes = classes
|
53
|
+
@classes = class_names(DEFAULT_ITEM_CLASSES, classes)
|
43
54
|
@attributes = attributes
|
44
55
|
end
|
45
56
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Ariadne
|
4
4
|
# Represents the top navigation bar on every page.
|
5
5
|
class HeaderComponent < Ariadne::Component
|
6
|
-
DEFAULT_CLASSES = "sticky top-0 z-50 px-4 py-
|
6
|
+
DEFAULT_CLASSES = "sticky top-0 z-50 px-4 py-5 bg-white shadow-sm shadow-slate-900/5 transition duration-500"
|
7
7
|
# flex flex-wrap items-center justify-between bg-white dark:shadow-none dark:bg-transparent
|
8
8
|
LINK_CLASSES = "rounded-lg py-1 px-2 text-slate-700 hover:bg-slate-100 hover:text-slate-900"
|
9
9
|
|
@@ -21,8 +21,8 @@ module Ariadne
|
|
21
21
|
|
22
22
|
TAG_TO_CLASSES = {
|
23
23
|
h1: "font-bold leading-7 sm:text-3xl",
|
24
|
-
h2: "text-3xl font-extrabold
|
25
|
-
h3: "text-2xl font-extrabold
|
24
|
+
h2: "text-3xl font-extrabold",
|
25
|
+
h3: "text-2xl font-extrabold",
|
26
26
|
}
|
27
27
|
# @example Default
|
28
28
|
# <%= render(Ariadne::HeadingComponent.new(tag: :h1)) { "H1 Text" } %>
|
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
<%=
|
3
|
-
|
4
|
-
|
5
|
-
<%= render(Ariadne::BaseComponent.new(tag: :span, classes: @text_classes, attributes: @attributes)) { content } if content.present? %>
|
6
|
-
</span>
|
1
|
+
<%= render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) do %>
|
2
|
+
<%= @icon.path.html_safe %>
|
3
|
+
<% end %>
|
4
|
+
<%= render(Ariadne::BaseComponent.new(tag: :span, classes: @text_classes, attributes: @text_attributes)) { content } if content.present? %>
|