Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sage dynamic select input - select2 #709

Merged
merged 16 commits into from Aug 23, 2021
Merged

Conversation

kajabijamell
Copy link
Contributor

@kajabijamell kajabijamell commented Aug 12, 2021

Description

Adds a select2 input type for sage forms

API Options:

url: String,
label: String,
name: String,
id: String,
has_error: [:optional, TrueClass],
message: [:optional, String],
required: [:optional, TrueClass],
// sets default selected option for the input
default_value: [:optional, String, Integer],
default_text: [:optional, String],
// enables pagination for 25 rows at a time
paginate: [:optional, TrueClass],
// allows user to search through retrieved results
search: [:optional, TrueClass],
// displays an x button for the user to clear the selected value
clear: [:optional, TrueClass],
placeholder: [:optional, String],
// toggles legacy select2 input preset options would be "sage" or "bootstrap"
theme: [:optional, String],

Screenshots

Component States

Empty state
image

Selected state
image

Input open w/ search
image

Input open w/o search
image

input w/ error
image

Testing in sage-lib

IMPORTANT

This input has dependencies that are only available in Kajabi Products. There's no way to test this from sage-lib.

Testing in kajabi-products

Testing is straightforward. You will need a URL generated from rails to deliver the select options via AJAX request. See component sample code here.

Examples of possible URLs can be found in the select_options controller found here in Kajabi Products app/controllers/admin/select_options_controller.rb.

Once you've found a URL to fetch data, you can then play with the different API attributes to reviews the input in different states. Screenshots are provided above as well.

This PR is additive, meaning it will not affect ant current implementation of the select2 inputs. It may be wise to double-check some existing select2 inputs just to make sure there's no overlap in styles or js.

  1. (LOW) Add dynamic select inputs to the sage-lib and does not affect any current components or code structures.

@kajabijamell kajabijamell self-assigned this Aug 12, 2021
@kajabijamell kajabijamell changed the title Jdj dynamic select input Sage dynamic select input - select2 Aug 12, 2021
Copy link
Contributor

@philschanely philschanely left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good here, @jamell-kajabi !

Regarding nesting depth, if its necessary (which in vendor situations like this would be understandable!) you can add /* stylelint-disable selector-max-compound-selectors */ before the set of styles that violate the rule and then /* stylelint-enable selector-max-compound-selectors */ afterwards.

One thing that would be great to add is some documentation around this and how it can be used. This is typically adding a folder and the set of files you can see for others inside docs/app/views/examples/components and then an entry for this component in docs/app/helpers/components_helper.rb. Then it will appear in the Components sidebar.

However, I understand following the other examples may not be 100% possible due to the asynchronous nature. It would be great to add the required files, document the props from your sage_dynamic_select.rb file similar to other components. But then if you can't easily show actual uses in the preview file, consider at least providing a code sample like what is shown on the Toast component.

I know this is going to be work well invested since this component is used so much in the app now. Thanks SO MUCh for doing this!! 🙇‍♂️

packages/sage-system/lib/dynamicSelect.js Show resolved Hide resolved
// empty state //
.sage-dynamic-select {
position: relative;
&__data {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we please move this out onto its own? We tend to avoid this type of use of & in Sage.

.sage-dynamic-select {
  // ...
} 

.sage-dynamic-select__data {
  // ...
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clarity, the goal is to avoid using & for segments of a particular element selector, but OK to use it for a whole element. So:

.block {
  &__element {
    // stuff
  }
  
  &--variant {
    &__element {
      // stuff
    }
  }
}

.block__element {
  // stuff

  .block--variant & {
    // stuff
  }
  
  &::after {
    // stuff
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And with the BEM naming we'd typically not nest an element selector inside a block selector so that the styles contained in a selector are ideally applied to that actual thing. If specificity or context is needed you bascially flip it so instead of:

.block {
  &--variant {
    &__element {
      // stuff
    }
  }
}

You do:

.block__element {
  // stuff

  .block--variant & {
    // stuff
  }
}

It is more typing (increased chance for typos 😬 ) but helps ensure each selector block is explicitly applying to that thing, thus preventing style leaks. Everything is also in one place for that particular thing too. Hope this makes sense. 👍 but if not please let me know and we can sync up. 🙌

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done :)

bottom: sage-spacing(xs);
left: 50%;
}
.select2-container--sage {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be nested for sufficient specificity, or could this be pulled out to avoid the extra nesting depth?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done 👍

height: $-dynamic-select-selected-height;
padding: $-dynamic-select-selected-padding;
border-color: $-dynamic-select-border-color;
.select2-selection__rendered {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here... if not needed, can this be pulled out a layer or more to avoid the deep nesting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@kajabijamell
Copy link
Contributor Author

kajabijamell commented Aug 13, 2021

Thank you for your review @philschanely! I was able to refactor some nesting which definitely helps with readability. I did have some questions regarding adding the input to our docs site, would love to sync with you around this.

Copy link
Member

@teenwolfblitzer teenwolfblitzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥 This is looking great, Jamell! Will be a substantial improvement to our select2 implementation in the app.

In addition to the nesting items that Phil suggested, my comments below are primarily on some cleanup and hopefully clearing up my understanding on derived values.

packages/sage-system/lib/dynamicSelect.js Outdated Show resolved Hide resolved
<%= component.generated_html_attributes.html_safe %>
name="<%= component.name %>"
id="<%= component.id %>"
tabindex="-1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for the group (no actionable items as of yet): we'll have to be mindful of this and the aria-hidden="true" below for accessibility. Select2 has been actively working on improving their compliance, but it's not quite there, so we'll have to keep a close watch on it.

@kajabijamell kajabijamell requested review from teenwolfblitzer, philschanely and sdhull and removed request for sdhull August 16, 2021 22:04
@teenwolfblitzer teenwolfblitzer requested a review from a team August 17, 2021 22:22
Copy link
Member

@teenwolfblitzer teenwolfblitzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏼 LGTM, a few minor edit tweaks to the preview copy but no major blockers that I can see. After testing with the bridge, I think we may need some additional design input re: the height change for selected values as a follow-up. Great work, this will be a useful addition!

clear: "Allow user to clear input value"

// Example Implementation
sage_component SageDynamicSelect, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @philschanely had mentioned earlier, ideally we'd have a rendered preview of the component in action, but this works as a substitute.

As a follow-up, I wonder if we could reference the external JS dependencies (jquery and select2) from a CDN just for this preview page. That'd give us a working preview but prevent the dependencies from being packaged up.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may be able to add them as peer dependencies in the repo. @voodooGQ would this make sense?

</p>

<h4>Error Handling</h4>
<p>Much like other sage inputs, the dynamic select includes options to render error messages from the server. By using the <code>has_error</code> attribute, one can trigger the erros states and print an error message that gets placed below the input.</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiny typo here "error states"

@@ -0,0 +1,42 @@
<h3>Working with the<code>Sage Dynamic Select Input (Select2)</code></h3>
<p>
The dynamic select input is a sagified version of the select2 input that resides in <code>Kajabi Products.</code> The input fuctionality leverages the Javascript library select2 and includes several options for tailoring the input to the UI. The input can retrieve options from any arbitrary API that will return validly structured JSON.<br/> <br/> Basic usage and complete documentation ca be found
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍 Beautifully written!

One suggestion, we can replace the <br> tags with a new <p>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note as well that the md() helper may be useful to simplify as well.

$-dynamic-select-placeholder-color: sage-color(gray, 400);
$-dynamic-select-color-success: map-get($sage-field-colors, success);
$-dynamic-select-border-box-shadow-size: map-get($sage-field-configs, box-shadow-size);
$-dynamic-select-selected-height: rem(54);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have an existing spec in Figma for this, so I won't consider it a blocker but do want to note that the height for the component is much taller (3.375rem) than the standard SageFormSelect field (2.25rem) with an option selected. This shouldn't be an issue for standalone fields, but in cases where inputs are horizontally aligned, the difference will be noticeable:

SageFormSelect SageDynamicSelect
selected-single selected-select2

@teenwolfblitzer teenwolfblitzer requested a review from a team August 18, 2021 01:59
Copy link
Contributor

@jed1976 jed1976 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really nice Jamell! Thanks so much for putting the time in to convert this to Sage. Will make an awesome addition to our collection. I left one comment, not a blocker. 👍🏼

packages/sage-system/lib/dynamicSelect.js Outdated Show resolved Hide resolved
Copy link
Contributor

@philschanely philschanely left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking in great shape, @jamell-kajabi ! Thanks for your hard work on this!

@kajabijamell kajabijamell merged commit e38f1ca into develop Aug 23, 2021
@kajabijamell kajabijamell mentioned this pull request Aug 23, 2021
5 tasks
@teenwolfblitzer teenwolfblitzer added this to the v4.13.x milestone Aug 23, 2021
@monicawheeler monicawheeler deleted the jdj-dynamic-select-input branch November 11, 2021 14:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants