block-kit 1.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.
- checksums.yaml +7 -0
- data/.rspec +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +183 -0
- data/Rakefile +8 -0
- data/lib/block_kit/base.rb +190 -0
- data/lib/block_kit/blocks.rb +50 -0
- data/lib/block_kit/composition/confirmation_dialog.rb +48 -0
- data/lib/block_kit/composition/conversation_filter.rb +42 -0
- data/lib/block_kit/composition/dispatch_action_config.rb +33 -0
- data/lib/block_kit/composition/input_parameter.rb +19 -0
- data/lib/block_kit/composition/mrkdwn.rb +15 -0
- data/lib/block_kit/composition/option.rb +41 -0
- data/lib/block_kit/composition/option_group.rb +27 -0
- data/lib/block_kit/composition/overflow_option.rb +21 -0
- data/lib/block_kit/composition/plain_text.rb +15 -0
- data/lib/block_kit/composition/slack_file.rb +36 -0
- data/lib/block_kit/composition/text.rb +29 -0
- data/lib/block_kit/composition/trigger.rb +33 -0
- data/lib/block_kit/composition/workflow.rb +19 -0
- data/lib/block_kit/composition.rb +19 -0
- data/lib/block_kit/concerns/confirmable.rb +21 -0
- data/lib/block_kit/concerns/conversation_selection.rb +26 -0
- data/lib/block_kit/concerns/dispatchable.rb +24 -0
- data/lib/block_kit/concerns/dsl_generation.rb +76 -0
- data/lib/block_kit/concerns/external.rb +19 -0
- data/lib/block_kit/concerns/focusable_on_load.rb +17 -0
- data/lib/block_kit/concerns/has_initial_option.rb +23 -0
- data/lib/block_kit/concerns/has_initial_options.rb +23 -0
- data/lib/block_kit/concerns/has_option_groups.rb +37 -0
- data/lib/block_kit/concerns/has_options.rb +28 -0
- data/lib/block_kit/concerns/has_placeholder.rb +21 -0
- data/lib/block_kit/concerns/has_rich_text_elements.rb +83 -0
- data/lib/block_kit/concerns/plain_text_emoji_assignment.rb +39 -0
- data/lib/block_kit/concerns.rb +18 -0
- data/lib/block_kit/elements/base.rb +23 -0
- data/lib/block_kit/elements/base_button.rb +45 -0
- data/lib/block_kit/elements/button.rb +27 -0
- data/lib/block_kit/elements/channels_select.rb +22 -0
- data/lib/block_kit/elements/checkboxes.rb +14 -0
- data/lib/block_kit/elements/conversations_select.rb +24 -0
- data/lib/block_kit/elements/date_picker.rb +21 -0
- data/lib/block_kit/elements/datetime_picker.rb +21 -0
- data/lib/block_kit/elements/email_text_input.rb +24 -0
- data/lib/block_kit/elements/external_select.rb +21 -0
- data/lib/block_kit/elements/file_input.rb +33 -0
- data/lib/block_kit/elements/image.rb +53 -0
- data/lib/block_kit/elements/multi_channels_select.rb +31 -0
- data/lib/block_kit/elements/multi_conversations_select.rb +33 -0
- data/lib/block_kit/elements/multi_external_select.rb +21 -0
- data/lib/block_kit/elements/multi_select.rb +21 -0
- data/lib/block_kit/elements/multi_static_select.rb +12 -0
- data/lib/block_kit/elements/multi_users_select.rb +31 -0
- data/lib/block_kit/elements/number_input.rb +52 -0
- data/lib/block_kit/elements/overflow.rb +23 -0
- data/lib/block_kit/elements/plain_text_input.rb +66 -0
- data/lib/block_kit/elements/radio_buttons.rb +14 -0
- data/lib/block_kit/elements/rich_text_input.rb +26 -0
- data/lib/block_kit/elements/select.rb +18 -0
- data/lib/block_kit/elements/static_select.rb +12 -0
- data/lib/block_kit/elements/time_picker.rb +43 -0
- data/lib/block_kit/elements/url_text_input.rb +24 -0
- data/lib/block_kit/elements/users_select.rb +17 -0
- data/lib/block_kit/elements/workflow_button.rb +18 -0
- data/lib/block_kit/elements.rb +36 -0
- data/lib/block_kit/fixers/associated.rb +27 -0
- data/lib/block_kit/fixers/base.rb +30 -0
- data/lib/block_kit/fixers/null_value.rb +42 -0
- data/lib/block_kit/fixers/truncate.rb +35 -0
- data/lib/block_kit/fixers.rb +11 -0
- data/lib/block_kit/layout/actions.rb +84 -0
- data/lib/block_kit/layout/base.rb +23 -0
- data/lib/block_kit/layout/context.rb +48 -0
- data/lib/block_kit/layout/divider.rb +9 -0
- data/lib/block_kit/layout/file.rb +19 -0
- data/lib/block_kit/layout/header.rb +22 -0
- data/lib/block_kit/layout/image.rb +61 -0
- data/lib/block_kit/layout/input.rb +119 -0
- data/lib/block_kit/layout/markdown.rb +19 -0
- data/lib/block_kit/layout/rich_text/elements/broadcast.rb +22 -0
- data/lib/block_kit/layout/rich_text/elements/channel.rb +21 -0
- data/lib/block_kit/layout/rich_text/elements/color.rb +20 -0
- data/lib/block_kit/layout/rich_text/elements/date.rb +34 -0
- data/lib/block_kit/layout/rich_text/elements/emoji.rb +27 -0
- data/lib/block_kit/layout/rich_text/elements/link.rb +28 -0
- data/lib/block_kit/layout/rich_text/elements/mention_style.rb +27 -0
- data/lib/block_kit/layout/rich_text/elements/text.rb +23 -0
- data/lib/block_kit/layout/rich_text/elements/text_style.rb +23 -0
- data/lib/block_kit/layout/rich_text/elements/user.rb +21 -0
- data/lib/block_kit/layout/rich_text/elements/usergroup.rb +21 -0
- data/lib/block_kit/layout/rich_text/elements.rb +35 -0
- data/lib/block_kit/layout/rich_text/list.rb +41 -0
- data/lib/block_kit/layout/rich_text/preformatted.rb +19 -0
- data/lib/block_kit/layout/rich_text/quote.rb +19 -0
- data/lib/block_kit/layout/rich_text/section.rb +11 -0
- data/lib/block_kit/layout/rich_text.rb +53 -0
- data/lib/block_kit/layout/section.rb +152 -0
- data/lib/block_kit/layout/video.rb +71 -0
- data/lib/block_kit/layout.rb +35 -0
- data/lib/block_kit/surfaces/base.rb +173 -0
- data/lib/block_kit/surfaces/home.rb +40 -0
- data/lib/block_kit/surfaces/message.rb +140 -0
- data/lib/block_kit/surfaces/modal.rb +74 -0
- data/lib/block_kit/surfaces.rb +11 -0
- data/lib/block_kit/typed_array.rb +114 -0
- data/lib/block_kit/typed_set.rb +78 -0
- data/lib/block_kit/types/array.rb +45 -0
- data/lib/block_kit/types/blocks.rb +37 -0
- data/lib/block_kit/types/generic.rb +45 -0
- data/lib/block_kit/types/option.rb +48 -0
- data/lib/block_kit/types/set.rb +35 -0
- data/lib/block_kit/types/text.rb +80 -0
- data/lib/block_kit/types.rb +17 -0
- data/lib/block_kit/validators/array_inclusion_validator.rb +55 -0
- data/lib/block_kit/validators/associated_validator.rb +61 -0
- data/lib/block_kit/validators.rb +8 -0
- data/lib/block_kit/version.rb +5 -0
- data/lib/block_kit.rb +38 -0
- metadata +190 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class File < Base
|
6
|
+
self.type = :file
|
7
|
+
|
8
|
+
MAX_EXTERNAL_ID_LENGTH = 255
|
9
|
+
|
10
|
+
attribute :external_id, :string
|
11
|
+
validates :external_id, presence: true, length: {maximum: MAX_EXTERNAL_ID_LENGTH}
|
12
|
+
fixes :external_id, truncate: {maximum: MAX_EXTERNAL_ID_LENGTH, dangerous: true}
|
13
|
+
|
14
|
+
def as_json(*)
|
15
|
+
super.merge(external_id: external_id, source: "remote").compact
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class Header < Base
|
6
|
+
self.type = :header
|
7
|
+
|
8
|
+
MAX_LENGTH = 150
|
9
|
+
|
10
|
+
plain_text_attribute :text
|
11
|
+
|
12
|
+
include Concerns::PlainTextEmojiAssignment.new(:text)
|
13
|
+
|
14
|
+
validates :text, presence: true, length: {maximum: MAX_LENGTH}
|
15
|
+
fixes :text, truncate: {maximum: MAX_LENGTH}
|
16
|
+
|
17
|
+
def as_json(*)
|
18
|
+
super.merge(text: text&.as_json)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module BlockKit
|
6
|
+
module Layout
|
7
|
+
class Image < Base
|
8
|
+
MAX_ALT_TEXT_LENGTH = 2000
|
9
|
+
MAX_IMAGE_URL_LENGTH = 3000
|
10
|
+
MAX_TITLE_LENGTH = 2000
|
11
|
+
|
12
|
+
self.type = :image
|
13
|
+
|
14
|
+
attribute :alt_text, :string
|
15
|
+
attribute :image_url, :string
|
16
|
+
attribute :slack_file, Types::Generic.of_type(Composition::SlackFile)
|
17
|
+
plain_text_attribute :title
|
18
|
+
|
19
|
+
include Concerns::PlainTextEmojiAssignment.new(:title)
|
20
|
+
|
21
|
+
validates :alt_text, presence: true, length: {maximum: MAX_ALT_TEXT_LENGTH}
|
22
|
+
fixes :alt_text, truncate: {maximum: MAX_ALT_TEXT_LENGTH}
|
23
|
+
|
24
|
+
validates :image_url, presence: true, length: {maximum: MAX_IMAGE_URL_LENGTH}, format: {with: URI::DEFAULT_PARSER.make_regexp(%w[http https]), message: "is not a valid URI", allow_blank: true}, allow_nil: true
|
25
|
+
fixes :image_url, truncate: {maximum: MAX_IMAGE_URL_LENGTH, dangerous: true, omission: ""}, null_value: {error_types: [:blank]}
|
26
|
+
|
27
|
+
validates :title, presence: true, length: {maximum: MAX_TITLE_LENGTH}, allow_nil: true
|
28
|
+
fixes :title, truncate: {maximum: MAX_TITLE_LENGTH}, null_value: {error_types: [:blank]}
|
29
|
+
|
30
|
+
validate :slack_file_or_url_present
|
31
|
+
|
32
|
+
def slack_file(attrs = {})
|
33
|
+
attrs = attrs.with_indifferent_access
|
34
|
+
return super() unless attrs.key?(:id) || attrs.key?(:url)
|
35
|
+
|
36
|
+
raise ArgumentError, "mutually exclusive keywords: :id, :url" if attrs.key?(:id) && attrs.key?(:url)
|
37
|
+
|
38
|
+
self.slack_file = Composition::SlackFile.new(**attrs.slice(:id, :url))
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def as_json(*)
|
44
|
+
super.merge(
|
45
|
+
alt_text: alt_text,
|
46
|
+
image_url: image_url,
|
47
|
+
slack_file: slack_file&.as_json,
|
48
|
+
title: title&.as_json
|
49
|
+
).compact
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def slack_file_or_url_present
|
55
|
+
if (slack_file.nil? && image_url.nil?) || (slack_file.present? && image_url.present?)
|
56
|
+
errors.add(:base, "must have either a slack_file or image_url but not both")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class Input < Base
|
6
|
+
self.type = :input
|
7
|
+
|
8
|
+
MAX_LABEL_LENGTH = 2000
|
9
|
+
MAX_HINT_LENGTH = 2000
|
10
|
+
SUPPORTED_ELEMENTS = [
|
11
|
+
Elements::ChannelsSelect,
|
12
|
+
Elements::Checkboxes,
|
13
|
+
Elements::ConversationsSelect,
|
14
|
+
Elements::DatePicker,
|
15
|
+
Elements::DatetimePicker,
|
16
|
+
Elements::EmailTextInput,
|
17
|
+
Elements::ExternalSelect,
|
18
|
+
Elements::FileInput,
|
19
|
+
Elements::MultiChannelsSelect,
|
20
|
+
Elements::MultiConversationsSelect,
|
21
|
+
Elements::MultiExternalSelect,
|
22
|
+
Elements::MultiStaticSelect,
|
23
|
+
Elements::MultiUsersSelect,
|
24
|
+
Elements::NumberInput,
|
25
|
+
Elements::PlainTextInput,
|
26
|
+
Elements::RadioButtons,
|
27
|
+
Elements::RichTextInput,
|
28
|
+
Elements::StaticSelect,
|
29
|
+
Elements::TimePicker,
|
30
|
+
Elements::UsersSelect,
|
31
|
+
Elements::URLTextInput
|
32
|
+
].freeze
|
33
|
+
|
34
|
+
plain_text_attribute :label
|
35
|
+
attribute :element, Types::Blocks.new(*SUPPORTED_ELEMENTS)
|
36
|
+
attribute :dispatch_action, :boolean
|
37
|
+
plain_text_attribute :hint
|
38
|
+
attribute :optional, :boolean
|
39
|
+
|
40
|
+
include Concerns::PlainTextEmojiAssignment.new(:label, :hint)
|
41
|
+
|
42
|
+
validates :label, presence: true, length: {maximum: MAX_LABEL_LENGTH}
|
43
|
+
fixes :label, truncate: {maximum: MAX_LABEL_LENGTH}
|
44
|
+
|
45
|
+
validates :element, presence: true, "block_kit/validators/associated": true
|
46
|
+
fixes :element, associated: true
|
47
|
+
|
48
|
+
validates :dispatch_action, inclusion: {in: [nil, false], message: "can't be enabled for FileInputs"}, if: ->(input) { input.element.is_a?(Elements::FileInput) }
|
49
|
+
fix :unset_dispatch_action_if_file_input
|
50
|
+
|
51
|
+
validates :hint, presence: true, length: {maximum: MAX_HINT_LENGTH}, allow_nil: true
|
52
|
+
fixes :hint, truncate: {maximum: MAX_HINT_LENGTH}, null_value: {error_types: [:blank]}
|
53
|
+
|
54
|
+
dsl_method :element, as: :channels_select, type: Elements::ChannelsSelect
|
55
|
+
dsl_method :element, as: :checkboxes, type: Elements::Checkboxes
|
56
|
+
dsl_method :element, as: :conversations_select, type: Elements::ConversationsSelect
|
57
|
+
dsl_method :element, as: :datepicker, type: Elements::DatePicker
|
58
|
+
dsl_method :element, as: :datetimepicker, type: Elements::DatetimePicker
|
59
|
+
dsl_method :element, as: :email_text_input, type: Elements::EmailTextInput
|
60
|
+
dsl_method :element, as: :external_select, type: Elements::ExternalSelect
|
61
|
+
dsl_method :element, as: :file_input, type: Elements::FileInput
|
62
|
+
dsl_method :element, as: :multi_channels_select, type: Elements::MultiChannelsSelect
|
63
|
+
dsl_method :element, as: :multi_conversations_select, type: Elements::MultiConversationsSelect
|
64
|
+
dsl_method :element, as: :multi_external_select, type: Elements::MultiExternalSelect
|
65
|
+
dsl_method :element, as: :multi_static_select, type: Elements::MultiStaticSelect, mutually_exclusive_fields: [:options, :option_groups]
|
66
|
+
dsl_method :element, as: :multi_users_select, type: Elements::MultiUsersSelect
|
67
|
+
dsl_method :element, as: :number_input, type: Elements::NumberInput
|
68
|
+
dsl_method :element, as: :plain_text_input, type: Elements::PlainTextInput
|
69
|
+
dsl_method :element, as: :radio_buttons, type: Elements::RadioButtons
|
70
|
+
dsl_method :element, as: :rich_text_input, type: Elements::RichTextInput
|
71
|
+
dsl_method :element, as: :static_select, type: Elements::StaticSelect, mutually_exclusive_fields: [:options, :option_groups]
|
72
|
+
dsl_method :element, as: :timepicker, type: Elements::TimePicker
|
73
|
+
dsl_method :element, as: :users_select, type: Elements::UsersSelect
|
74
|
+
dsl_method :element, as: :url_text_input, type: Elements::URLTextInput
|
75
|
+
|
76
|
+
alias_method :channel_select, :channels_select
|
77
|
+
alias_method :conversation_select, :conversations_select
|
78
|
+
alias_method :date_picker, :datepicker
|
79
|
+
alias_method :datetime_picker, :datetimepicker
|
80
|
+
alias_method :email_input, :email_text_input
|
81
|
+
alias_method :multi_channel_select, :multi_channels_select
|
82
|
+
alias_method :multi_conversation_select, :multi_conversations_select
|
83
|
+
alias_method :multi_user_select, :multi_users_select
|
84
|
+
alias_method :text_input, :plain_text_input
|
85
|
+
alias_method :time_picker, :timepicker
|
86
|
+
alias_method :user_select, :users_select
|
87
|
+
|
88
|
+
def optional?
|
89
|
+
!!optional
|
90
|
+
end
|
91
|
+
|
92
|
+
def required?
|
93
|
+
!optional?
|
94
|
+
end
|
95
|
+
|
96
|
+
def dispatch_action?
|
97
|
+
!!dispatch_action
|
98
|
+
end
|
99
|
+
|
100
|
+
def as_json(*)
|
101
|
+
super.merge(
|
102
|
+
label: label&.as_json,
|
103
|
+
element: element&.as_json,
|
104
|
+
dispatch_action: dispatch_action,
|
105
|
+
hint: hint&.as_json,
|
106
|
+
optional: optional
|
107
|
+
).compact
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def unset_dispatch_action_if_file_input
|
113
|
+
if dispatch_action? && element.is_a?(Elements::FileInput)
|
114
|
+
self.dispatch_action = false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class Markdown < Base
|
6
|
+
self.type = :markdown
|
7
|
+
|
8
|
+
MAX_LENGTH = 12_000
|
9
|
+
|
10
|
+
attribute :text, :string
|
11
|
+
validates :text, presence: true, length: {maximum: MAX_LENGTH}
|
12
|
+
fixes :text, truncate: {maximum: MAX_LENGTH}
|
13
|
+
|
14
|
+
def as_json(*)
|
15
|
+
super.merge(text: text).compact
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Elements::Broadcast < BlockKit::Base
|
6
|
+
self.type = :broadcast
|
7
|
+
|
8
|
+
VALID_RANGES = [
|
9
|
+
HERE = "here",
|
10
|
+
EVERYONE = "everyone",
|
11
|
+
CHANNEL = "channel"
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
attribute :range, :string
|
15
|
+
validates :range, presence: true, inclusion: {in: VALID_RANGES}
|
16
|
+
|
17
|
+
def as_json(*)
|
18
|
+
super.merge(range: range).compact
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Elements::Channel < BlockKit::Base
|
6
|
+
self.type = :channel
|
7
|
+
|
8
|
+
attribute :channel_id, :string
|
9
|
+
attribute :style, Types::Generic.of_type(RichText::Elements::MentionStyle)
|
10
|
+
|
11
|
+
validates :channel_id, presence: true
|
12
|
+
|
13
|
+
def as_json(*)
|
14
|
+
super.merge(
|
15
|
+
channel_id: channel_id,
|
16
|
+
style: style&.as_json
|
17
|
+
).compact
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Elements::Color < BlockKit::Base
|
6
|
+
self.type = :color
|
7
|
+
|
8
|
+
attribute :value, :string
|
9
|
+
|
10
|
+
# Slack accepts both hex codes _and_ extended CSS3 color names. However,
|
11
|
+
# they don't actually validate that the value is a real color; they just
|
12
|
+
# display white if it isn't, while allowing the block itself to be valid.
|
13
|
+
validates :value, presence: true
|
14
|
+
|
15
|
+
def as_json(*)
|
16
|
+
super.merge(value: value).compact
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module BlockKit
|
6
|
+
module Layout
|
7
|
+
class RichText::Elements::Date < BlockKit::Base
|
8
|
+
self.type = :date
|
9
|
+
|
10
|
+
attribute :timestamp, :datetime
|
11
|
+
attribute :format, :string
|
12
|
+
attribute :url, :string
|
13
|
+
attribute :fallback, :string
|
14
|
+
|
15
|
+
validates :timestamp, presence: true
|
16
|
+
validates :format, presence: true
|
17
|
+
|
18
|
+
validates :url, presence: true, format: {with: URI::DEFAULT_PARSER.make_regexp, message: "is not a valid URI", allow_blank: true}, allow_nil: true
|
19
|
+
fixes :url, null_value: {error_types: [:blank]}
|
20
|
+
|
21
|
+
validates :fallback, presence: true, allow_nil: true
|
22
|
+
fixes :fallback, null_value: {error_types: [:blank]}
|
23
|
+
|
24
|
+
def as_json(*)
|
25
|
+
super.merge(
|
26
|
+
timestamp: timestamp.to_i,
|
27
|
+
format: format,
|
28
|
+
url: url,
|
29
|
+
fallback: fallback
|
30
|
+
).compact
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Elements::Emoji < BlockKit::Base
|
6
|
+
self.type = :emoji
|
7
|
+
|
8
|
+
attribute :name, :string
|
9
|
+
attribute :unicode, :string
|
10
|
+
|
11
|
+
validates :name, presence: true
|
12
|
+
validates :unicode, presence: true, format: {with: /\A[0-9a-f-]+\z/}, allow_nil: true
|
13
|
+
fixes :unicode, null_value: {error_types: [:blank]}
|
14
|
+
|
15
|
+
def unicode=(value)
|
16
|
+
super(value&.to_s&.downcase)
|
17
|
+
end
|
18
|
+
|
19
|
+
def as_json(*)
|
20
|
+
super.merge(
|
21
|
+
name: name,
|
22
|
+
unicode: unicode
|
23
|
+
).compact
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module BlockKit
|
6
|
+
module Layout
|
7
|
+
class RichText::Elements::Link < BlockKit::Base
|
8
|
+
self.type = :link
|
9
|
+
|
10
|
+
attribute :url, :string
|
11
|
+
attribute :text, :string
|
12
|
+
attribute :unsafe, :boolean
|
13
|
+
attribute :style, Types::Generic.of_type(RichText::Elements::TextStyle)
|
14
|
+
|
15
|
+
validates :url, presence: true, format: {with: URI::DEFAULT_PARSER.make_regexp, message: "is not a valid URI", allow_blank: true}
|
16
|
+
validates :text, presence: true
|
17
|
+
|
18
|
+
def as_json(*)
|
19
|
+
super.merge(
|
20
|
+
url: url,
|
21
|
+
text: text,
|
22
|
+
unsafe: unsafe,
|
23
|
+
style: style&.as_json
|
24
|
+
).compact
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Elements::MentionStyle < BlockKit::Base
|
6
|
+
self.type = :rich_text_element_mention_style
|
7
|
+
|
8
|
+
attribute :bold, :boolean
|
9
|
+
attribute :italic, :boolean
|
10
|
+
attribute :strike, :boolean
|
11
|
+
attribute :highlight, :boolean
|
12
|
+
attribute :client_highlight, :boolean
|
13
|
+
attribute :unlink, :boolean
|
14
|
+
|
15
|
+
def as_json(*)
|
16
|
+
{
|
17
|
+
bold: bold,
|
18
|
+
italic: italic,
|
19
|
+
strike: strike,
|
20
|
+
highlight: highlight,
|
21
|
+
client_highlight: client_highlight,
|
22
|
+
unlink: unlink
|
23
|
+
}.compact
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module BlockKit
|
6
|
+
module Layout
|
7
|
+
class RichText::Elements::Text < BlockKit::Base
|
8
|
+
self.type = :text
|
9
|
+
|
10
|
+
attribute :text, :string
|
11
|
+
attribute :style, Types::Generic.of_type(RichText::Elements::TextStyle)
|
12
|
+
|
13
|
+
validates :text, presence: true
|
14
|
+
|
15
|
+
def as_json(*)
|
16
|
+
super.merge(
|
17
|
+
text: text,
|
18
|
+
style: style&.as_json
|
19
|
+
).compact
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Elements::TextStyle < BlockKit::Base
|
6
|
+
self.type = :rich_text_element_text_style
|
7
|
+
|
8
|
+
attribute :bold, :boolean
|
9
|
+
attribute :italic, :boolean
|
10
|
+
attribute :strike, :boolean
|
11
|
+
attribute :code, :boolean
|
12
|
+
|
13
|
+
def as_json(*)
|
14
|
+
{
|
15
|
+
bold: bold,
|
16
|
+
italic: italic,
|
17
|
+
strike: strike,
|
18
|
+
code: code
|
19
|
+
}.compact
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Elements::User < BlockKit::Base
|
6
|
+
self.type = :user
|
7
|
+
|
8
|
+
attribute :user_id, :string
|
9
|
+
attribute :style, Types::Generic.of_type(RichText::Elements::MentionStyle)
|
10
|
+
|
11
|
+
validates :user_id, presence: true
|
12
|
+
|
13
|
+
def as_json(*)
|
14
|
+
super.merge(
|
15
|
+
user_id: user_id,
|
16
|
+
style: style&.as_json
|
17
|
+
).compact
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Elements::Usergroup < BlockKit::Base
|
6
|
+
self.type = :Usergroup
|
7
|
+
|
8
|
+
attribute :usergroup_id, :string
|
9
|
+
attribute :style, Types::Generic.of_type(RichText::Elements::MentionStyle)
|
10
|
+
|
11
|
+
validates :usergroup_id, presence: true
|
12
|
+
|
13
|
+
def as_json(*)
|
14
|
+
super.merge(
|
15
|
+
usergroup_id: usergroup_id,
|
16
|
+
style: style&.as_json
|
17
|
+
).compact
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
module RichText::Elements
|
6
|
+
autoload :Broadcast, "block_kit/layout/rich_text/elements/broadcast"
|
7
|
+
autoload :Channel, "block_kit/layout/rich_text/elements/channel"
|
8
|
+
autoload :Color, "block_kit/layout/rich_text/elements/color"
|
9
|
+
autoload :Date, "block_kit/layout/rich_text/elements/date"
|
10
|
+
autoload :Emoji, "block_kit/layout/rich_text/elements/emoji"
|
11
|
+
autoload :Link, "block_kit/layout/rich_text/elements/link"
|
12
|
+
autoload :Text, "block_kit/layout/rich_text/elements/text"
|
13
|
+
autoload :User, "block_kit/layout/rich_text/elements/user"
|
14
|
+
autoload :Usergroup, "block_kit/layout/rich_text/elements/usergroup"
|
15
|
+
|
16
|
+
# Utility blocks
|
17
|
+
autoload :MentionStyle, "block_kit/layout/rich_text/elements/mention_style"
|
18
|
+
autoload :TextStyle, "block_kit/layout/rich_text/elements/text_style"
|
19
|
+
|
20
|
+
def self.all
|
21
|
+
@all ||= [
|
22
|
+
Broadcast,
|
23
|
+
Channel,
|
24
|
+
Color,
|
25
|
+
Date,
|
26
|
+
Emoji,
|
27
|
+
Link,
|
28
|
+
Text,
|
29
|
+
User,
|
30
|
+
Usergroup
|
31
|
+
].freeze
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::List < BlockKit::Base
|
6
|
+
self.type = :rich_text_list
|
7
|
+
|
8
|
+
VALID_STYLES = [
|
9
|
+
BULLET = "bullet",
|
10
|
+
ORDERED = "ordered"
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
attribute :style, :string
|
14
|
+
attribute :elements, Types::Array.of(RichText::Section)
|
15
|
+
attribute :indent, :integer
|
16
|
+
attribute :offset, :integer
|
17
|
+
attribute :border, :integer
|
18
|
+
|
19
|
+
validates :style, presence: true, inclusion: {in: VALID_STYLES}
|
20
|
+
validates :elements, presence: true, "block_kit/validators/associated": true
|
21
|
+
validates :indent, numericality: {only_integer: true, greater_than_or_equal_to: 0}, allow_nil: true
|
22
|
+
validates :offset, numericality: {only_integer: true, greater_than_or_equal_to: 0}, allow_nil: true
|
23
|
+
validates :border, numericality: {only_integer: true, greater_than_or_equal_to: 0}, allow_nil: true
|
24
|
+
|
25
|
+
fixes :elements, associated: true
|
26
|
+
|
27
|
+
dsl_method :elements, as: :section, type: RichText::Section
|
28
|
+
alias_method :rich_text_section, :section
|
29
|
+
|
30
|
+
def as_json(*)
|
31
|
+
super.merge(
|
32
|
+
style: style,
|
33
|
+
elements: elements&.map(&:as_json),
|
34
|
+
indent: indent,
|
35
|
+
offset: offset,
|
36
|
+
border: border
|
37
|
+
).compact
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Preformatted < BlockKit::Base
|
6
|
+
self.type = :rich_text_preformatted
|
7
|
+
|
8
|
+
include Concerns::HasRichTextElements
|
9
|
+
|
10
|
+
attribute :border, :integer
|
11
|
+
validates :border, numericality: {only_integer: true, greater_than_or_equal_to: 0}, allow_nil: true
|
12
|
+
fixes :border, null_value: {error_types: [:greater_than_or_equal_to]}
|
13
|
+
|
14
|
+
def as_json(*)
|
15
|
+
super.merge(border: border).compact
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlockKit
|
4
|
+
module Layout
|
5
|
+
class RichText::Quote < BlockKit::Base
|
6
|
+
self.type = :rich_text_quote
|
7
|
+
|
8
|
+
include Concerns::HasRichTextElements
|
9
|
+
|
10
|
+
attribute :border, :integer
|
11
|
+
validates :border, numericality: {only_integer: true, greater_than_or_equal_to: 0}, allow_nil: true
|
12
|
+
fixes :border, null_value: {error_types: [:greater_than_or_equal_to]}
|
13
|
+
|
14
|
+
def as_json(*)
|
15
|
+
super.merge(border: border).compact
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|