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.
Files changed (120) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +5 -0
  3. data/CODE_OF_CONDUCT.md +132 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +183 -0
  6. data/Rakefile +8 -0
  7. data/lib/block_kit/base.rb +190 -0
  8. data/lib/block_kit/blocks.rb +50 -0
  9. data/lib/block_kit/composition/confirmation_dialog.rb +48 -0
  10. data/lib/block_kit/composition/conversation_filter.rb +42 -0
  11. data/lib/block_kit/composition/dispatch_action_config.rb +33 -0
  12. data/lib/block_kit/composition/input_parameter.rb +19 -0
  13. data/lib/block_kit/composition/mrkdwn.rb +15 -0
  14. data/lib/block_kit/composition/option.rb +41 -0
  15. data/lib/block_kit/composition/option_group.rb +27 -0
  16. data/lib/block_kit/composition/overflow_option.rb +21 -0
  17. data/lib/block_kit/composition/plain_text.rb +15 -0
  18. data/lib/block_kit/composition/slack_file.rb +36 -0
  19. data/lib/block_kit/composition/text.rb +29 -0
  20. data/lib/block_kit/composition/trigger.rb +33 -0
  21. data/lib/block_kit/composition/workflow.rb +19 -0
  22. data/lib/block_kit/composition.rb +19 -0
  23. data/lib/block_kit/concerns/confirmable.rb +21 -0
  24. data/lib/block_kit/concerns/conversation_selection.rb +26 -0
  25. data/lib/block_kit/concerns/dispatchable.rb +24 -0
  26. data/lib/block_kit/concerns/dsl_generation.rb +76 -0
  27. data/lib/block_kit/concerns/external.rb +19 -0
  28. data/lib/block_kit/concerns/focusable_on_load.rb +17 -0
  29. data/lib/block_kit/concerns/has_initial_option.rb +23 -0
  30. data/lib/block_kit/concerns/has_initial_options.rb +23 -0
  31. data/lib/block_kit/concerns/has_option_groups.rb +37 -0
  32. data/lib/block_kit/concerns/has_options.rb +28 -0
  33. data/lib/block_kit/concerns/has_placeholder.rb +21 -0
  34. data/lib/block_kit/concerns/has_rich_text_elements.rb +83 -0
  35. data/lib/block_kit/concerns/plain_text_emoji_assignment.rb +39 -0
  36. data/lib/block_kit/concerns.rb +18 -0
  37. data/lib/block_kit/elements/base.rb +23 -0
  38. data/lib/block_kit/elements/base_button.rb +45 -0
  39. data/lib/block_kit/elements/button.rb +27 -0
  40. data/lib/block_kit/elements/channels_select.rb +22 -0
  41. data/lib/block_kit/elements/checkboxes.rb +14 -0
  42. data/lib/block_kit/elements/conversations_select.rb +24 -0
  43. data/lib/block_kit/elements/date_picker.rb +21 -0
  44. data/lib/block_kit/elements/datetime_picker.rb +21 -0
  45. data/lib/block_kit/elements/email_text_input.rb +24 -0
  46. data/lib/block_kit/elements/external_select.rb +21 -0
  47. data/lib/block_kit/elements/file_input.rb +33 -0
  48. data/lib/block_kit/elements/image.rb +53 -0
  49. data/lib/block_kit/elements/multi_channels_select.rb +31 -0
  50. data/lib/block_kit/elements/multi_conversations_select.rb +33 -0
  51. data/lib/block_kit/elements/multi_external_select.rb +21 -0
  52. data/lib/block_kit/elements/multi_select.rb +21 -0
  53. data/lib/block_kit/elements/multi_static_select.rb +12 -0
  54. data/lib/block_kit/elements/multi_users_select.rb +31 -0
  55. data/lib/block_kit/elements/number_input.rb +52 -0
  56. data/lib/block_kit/elements/overflow.rb +23 -0
  57. data/lib/block_kit/elements/plain_text_input.rb +66 -0
  58. data/lib/block_kit/elements/radio_buttons.rb +14 -0
  59. data/lib/block_kit/elements/rich_text_input.rb +26 -0
  60. data/lib/block_kit/elements/select.rb +18 -0
  61. data/lib/block_kit/elements/static_select.rb +12 -0
  62. data/lib/block_kit/elements/time_picker.rb +43 -0
  63. data/lib/block_kit/elements/url_text_input.rb +24 -0
  64. data/lib/block_kit/elements/users_select.rb +17 -0
  65. data/lib/block_kit/elements/workflow_button.rb +18 -0
  66. data/lib/block_kit/elements.rb +36 -0
  67. data/lib/block_kit/fixers/associated.rb +27 -0
  68. data/lib/block_kit/fixers/base.rb +30 -0
  69. data/lib/block_kit/fixers/null_value.rb +42 -0
  70. data/lib/block_kit/fixers/truncate.rb +35 -0
  71. data/lib/block_kit/fixers.rb +11 -0
  72. data/lib/block_kit/layout/actions.rb +84 -0
  73. data/lib/block_kit/layout/base.rb +23 -0
  74. data/lib/block_kit/layout/context.rb +48 -0
  75. data/lib/block_kit/layout/divider.rb +9 -0
  76. data/lib/block_kit/layout/file.rb +19 -0
  77. data/lib/block_kit/layout/header.rb +22 -0
  78. data/lib/block_kit/layout/image.rb +61 -0
  79. data/lib/block_kit/layout/input.rb +119 -0
  80. data/lib/block_kit/layout/markdown.rb +19 -0
  81. data/lib/block_kit/layout/rich_text/elements/broadcast.rb +22 -0
  82. data/lib/block_kit/layout/rich_text/elements/channel.rb +21 -0
  83. data/lib/block_kit/layout/rich_text/elements/color.rb +20 -0
  84. data/lib/block_kit/layout/rich_text/elements/date.rb +34 -0
  85. data/lib/block_kit/layout/rich_text/elements/emoji.rb +27 -0
  86. data/lib/block_kit/layout/rich_text/elements/link.rb +28 -0
  87. data/lib/block_kit/layout/rich_text/elements/mention_style.rb +27 -0
  88. data/lib/block_kit/layout/rich_text/elements/text.rb +23 -0
  89. data/lib/block_kit/layout/rich_text/elements/text_style.rb +23 -0
  90. data/lib/block_kit/layout/rich_text/elements/user.rb +21 -0
  91. data/lib/block_kit/layout/rich_text/elements/usergroup.rb +21 -0
  92. data/lib/block_kit/layout/rich_text/elements.rb +35 -0
  93. data/lib/block_kit/layout/rich_text/list.rb +41 -0
  94. data/lib/block_kit/layout/rich_text/preformatted.rb +19 -0
  95. data/lib/block_kit/layout/rich_text/quote.rb +19 -0
  96. data/lib/block_kit/layout/rich_text/section.rb +11 -0
  97. data/lib/block_kit/layout/rich_text.rb +53 -0
  98. data/lib/block_kit/layout/section.rb +152 -0
  99. data/lib/block_kit/layout/video.rb +71 -0
  100. data/lib/block_kit/layout.rb +35 -0
  101. data/lib/block_kit/surfaces/base.rb +173 -0
  102. data/lib/block_kit/surfaces/home.rb +40 -0
  103. data/lib/block_kit/surfaces/message.rb +140 -0
  104. data/lib/block_kit/surfaces/modal.rb +74 -0
  105. data/lib/block_kit/surfaces.rb +11 -0
  106. data/lib/block_kit/typed_array.rb +114 -0
  107. data/lib/block_kit/typed_set.rb +78 -0
  108. data/lib/block_kit/types/array.rb +45 -0
  109. data/lib/block_kit/types/blocks.rb +37 -0
  110. data/lib/block_kit/types/generic.rb +45 -0
  111. data/lib/block_kit/types/option.rb +48 -0
  112. data/lib/block_kit/types/set.rb +35 -0
  113. data/lib/block_kit/types/text.rb +80 -0
  114. data/lib/block_kit/types.rb +17 -0
  115. data/lib/block_kit/validators/array_inclusion_validator.rb +55 -0
  116. data/lib/block_kit/validators/associated_validator.rb +61 -0
  117. data/lib/block_kit/validators.rb +8 -0
  118. data/lib/block_kit/version.rb +5 -0
  119. data/lib/block_kit.rb +38 -0
  120. 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
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlockKit
4
+ module Layout
5
+ class RichText::Section < BlockKit::Base
6
+ self.type = :rich_text_section
7
+
8
+ include Concerns::HasRichTextElements
9
+ end
10
+ end
11
+ end