Skip to content

Commit

Permalink
feat: plaintext input (#128)
Browse files Browse the repository at this point in the history
  • Loading branch information
cakekindel authored May 19, 2021
1 parent 9383390 commit aaaf764
Show file tree
Hide file tree
Showing 6 changed files with 440 additions and 12 deletions.
4 changes: 4 additions & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ command = "cargo"
args = ["fmt"]
dependencies = ["install-fmt"]

[tasks.doctest-slow]
command = "cargo"
args = ["--locked", "test", "--jobs", "1", "--doc", "--", "--quiet"]

[tasks.doctest]
command = "cargo"
args = ["--locked", "test", "--doc", "--", "--quiet"]
Expand Down
9 changes: 8 additions & 1 deletion src/block_elements/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pub use button::Contents as Button;
pub mod select;
pub use select::Select;

pub mod text_input;
pub use text_input::TextInput;

/// # Block Elements - interactive components
/// [slack api docs 🔗](https://api.slack.com/reference/block-kit/block-elements)
///
Expand All @@ -34,9 +37,11 @@ pub enum BlockElement<'a> {
Image,
MultiSelect,
OverflowMenu,
PlainInput,
RadioButtons(Radio<'a>),

#[serde(rename = "plain_text_input")]
TextInput(TextInput<'a>),

#[serde(rename = "channels_select")]
SelectPublicChannel(select::PublicChannel<'a>),

Expand All @@ -62,13 +67,15 @@ impl<'a> BlockElement<'a> {
| Self::SelectUser(cts) => cts.validate(),
| Self::SelectExternal(cts) => cts.validate(),
| Self::SelectStatic(cts) => cts.validate(),
| Self::RadioButtons(cts) => cts.validate(),
| rest => todo!("validation not implemented for {:?}", rest),
}
}
}

convert!(impl From<Button> for BlockElement<'static> => |b| BlockElement::Button(b));
convert!(impl<'a> From<Radio<'a>> for BlockElement<'a> => |b| BlockElement::RadioButtons(b));
convert!(impl<'a> From<TextInput<'a>> for BlockElement<'a> => |t| BlockElement::TextInput(t));

convert!(impl<'a> From<Select<'a>> for BlockElement<'a>
=> |s| match s {
Expand Down
66 changes: 62 additions & 4 deletions src/block_elements/radio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ use crate::{compose::{opt::{AnyText, UrlUnset},

pub type MyOpt<'a> = Opt<'a, AnyText, UrlUnset>;

/// # Radio Buttons
///
/// A radio button group that allows a user to choose one item from a list of possible options.
///
/// Works in [blocks ]: Section, Actions, Input
/// Works in [app surfaces ]: Home tabs, Modals, Messages
/// [slack api docs 🔗]
///
/// Works in [blocks 🔗]: Section, Actions, Input
/// Works in [app surfaces 🔗]: Home tabs, Modals, Messages
///
/// [blocks ]: https://api.slack.com/reference/block-kit/blocks
/// [app surfaces ]: https://api.slack.com/surfaces
/// [slack api docs 🔗]: https://api.slack.com/reference/block-kit/block-elements#radio
/// [blocks 🔗]: https://api.slack.com/reference/block-kit/blocks
/// [app surfaces 🔗]: https://api.slack.com/surfaces
#[derive(Clone, Debug, Hash, PartialEq, Ser, De, Validate)]
pub struct Radio<'a> {
#[validate(length(max = 255))]
Expand All @@ -37,10 +42,42 @@ pub struct Radio<'a> {
}

impl<'a> Radio<'a> {
/// Build a new Radio Button Group
///
/// # Example
/// See docs for `RadioBuilder`.
pub fn builder() -> build::RadioBuilderInit<'a> {
build::RadioBuilderInit::new()
}

/// Validate that this select element agrees with Slack's model requirements
///
/// # Errors
/// - length of `action_id` greater than 255
/// - length of `options` greater than 10
/// - one or more of `options` is invalid
/// - `initial_option` is set and an invalid `Opt`
/// - `confirm` is set and an invalid `Confirm`
///
/// # Example
/// ```
/// use slack_blocks::{block_elements::Radio, compose::Opt};
///
/// fn repeat<T: Copy>(el: T, n: usize) -> impl Iterator<Item = T> {
/// std::iter::repeat(el).take(n)
/// }
///
/// let long_string: String = repeat('a', 256).collect();
/// let opt = Opt::builder().text_md("foo").value("bar").build();
///
/// let opts = repeat(&opt, 11).map(|o| o.clone()).collect::<Vec<_>>();
///
/// let input = Radio::builder().action_id(long_string)
/// .options(opts)
/// .build();
///
/// assert!(matches!(input.validate(), Err(_)))
/// ```
pub fn validate(&self) -> ValidationResult {
Validate::validate(self)
}
Expand Down Expand Up @@ -101,6 +138,7 @@ pub mod build {
}

impl<'a, T, A, O> RadioBuilder<'a, T, A, O> {
/// Construct a new RadioBuilder
pub fn new() -> Self {
Self { action_id: None,
options: None,
Expand Down Expand Up @@ -201,6 +239,26 @@ pub mod build {
}

impl<'a, T> RadioBuilder<'a, T, Set<method::action_id>, Set<method::options>> {
/// All done building, now give me a darn radio button group!
///
/// > `no method name 'build' found for struct 'RadioBuilder<...>'`?
/// Make sure all required setter methods have been called. See docs for `RadioBuilder`.
///
/// ```compile_fail
/// use slack_blocks::block_elements::Radio;
///
/// let foo = Radio::builder().build(); // Won't compile!
/// ```
///
/// ```
/// use slack_blocks::{block_elements::Radio, compose::Opt};
///
/// let foo = Radio::builder().action_id("bar")
/// .options(vec![Opt::builder().text_md("foo")
/// .value("bar")
/// .build()])
/// .build();
/// ```
pub fn build(self) -> Radio<'a> {
Radio { action_id: self.action_id.unwrap(),
options: self.options.unwrap(),
Expand Down
Loading

0 comments on commit aaaf764

Please sign in to comment.