Skip to content

Commit

Permalink
Merge pull request #709 from Kajabi/jdj-dynamic-select-input
Browse files Browse the repository at this point in the history
Sage dynamic select input - select2
  • Loading branch information
kajabijamell committed Aug 23, 2021
2 parents 636802f + 0fbd075 commit e38f1ca
Show file tree
Hide file tree
Showing 13 changed files with 412 additions and 1 deletion.
9 changes: 9 additions & 0 deletions docs/app/helpers/components_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ def sage_components
react: "todo",
a11y: "done"
},
{
title: "dynamic_select",
description: "A description is about the dynamic select.",
scss: "done",
docs: "todo",
rails: "done",
react: "todo",
a11y: "todo"
},
{
title: "form_input",
description: "Basic text input form fields with 'floating' labels",
Expand Down
Original file line number Diff line number Diff line change
@@ -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
<a href="https://select2.org/getting-started/basic-usage" target="_blank"><code>here</code></a>.
</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>

<pre class="prettyprint">
<code>
// Component API
name: "Input Form Name",
label: "Input Label",
id: "Input id",
required: true
has_error: false
message: "Error message goes here"
url: "Endpoint for API",
default_value: "Prefill select input with default value",
default_text: "Prefill select input with default title",
theme: "Choose Sage or Bootstrap for legacy input",
search: "Allow user to search through retrieved results",
clear: "Allow user to clear input value"

// Example Implementation
sage_component SageDynamicSelect, {
name: "site[home_landing_page_id]",
label: "Landing Page",
id: "site_home_landing_page_id",
url: admin_site_select_options_path(site, :landing_page, { published: true }, format: :json),
default_value: site.home_landing_page.id,
default_text: site.home_landing_page.title,
theme: "sage",
search: true,
clear: false
}

</code>
</pre>


84 changes: 84 additions & 0 deletions docs/app/views/examples/components/dynamic_select/_props.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<tr>
<td><%= md('`url`') %></td>
<td><%= md('API URL for retrieving select options') %></td>
<td><%= md('String') %></td>
<td><%= md('`nil`') %></td>
</tr>
<tr>
<td><%= md('`label`') %></td>
<td><%= md('Label for the input') %></td>
<td><%= md('String') %></td>
<td><%= md('`component.id`') %></td>
</tr>
<tr>
<td><%= md('`name`') %></td>
<td><%= md('Input name') %></td>
<td><%= md('String') %></td>
<td><%= md('`nil`') %></td>
</tr>
<tr>
<td><%= md('`id`') %></td>
<td><%= md('Input ID') %></td>
<td><%= md('String') %></td>
<td><%= md('`nil`') %></td>
</tr>
<tr>
<td><%= md('`has_error`') %></td>
<td><%= md('Enabling this property adds the `.sage-input--error` class to the component.') %></td>
<td><%= md('Boolean') %></td>
<td><%= md('`nil`') %></td>
</tr>
<tr>
<td><%= md('`message`') %></td>
<td><%= md('Sets the message text for the component.') %></td>
<td><%= md('String') %></td>
<td><%= md('`nil`') %></td>
</tr>
<tr>
<td><%= md('`placeholder`') %></td>
<td><%= md('Displays placeholder text when the input is empty.') %></td>
<td><%= md('String') %></td>
<td><%= md('`component.label || component.id`') %></td>
</tr>
<tr>
<td><%= md('`default_value`') %></td>
<td><%= md('Default value for the input') %></td>
<td><%= md('String') %></td>
<td><%= md('`nil`') %></td>
</tr>
<tr>
<td><%= md('`default_text`') %></td>
<td><%= md('Default text for the input') %></td>
<td><%= md('String') %></td>
<td><%= md('`nil`') %></td>
</tr>
<tr>
<td><%= md('`paginate`') %></td>
<td><%= md('Allows input to paginate results per 25 items') %></td>
<td><%= md('Boolean') %></td>
<td><%= md('`nil`') %></td>
</tr>
<tr>
<td><%= md('`search`') %></td>
<td><%= md('Displays a search bar for users to search through results') %></td>
<td><%= md('Boolean') %></td>
<td><%= md('`false`') %></td>
</tr>
<tr>
<td><%= md('`clear`') %></td>
<td><%= md('Displays an "x" button for users to clear the current value.') %></td>
<td><%= md('Boolean') %></td>
<td><%= md('`false`') %></td>
</tr>
<tr>
<td><%= md('`required`') %></td>
<td><%= md('Makes input selection required') %></td>
<td><%= md('Boolean') %></td>
<td><%= md('`nil`') %></td>
</tr>
<tr>
<td><%= md('`theme`') %></td>
<td><%= md('Choose from legacy UI or Sage') %></td>
<td><%= md('string') %></td>
<td><%= md('`sage`') %></td>
</tr>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

19 changes: 19 additions & 0 deletions docs/lib/sage_rails/app/sage_components/sage_dynamic_select.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class SageDynamicSelect < SageComponent
set_attribute_schema({
url: String,
label: String,
name: String,
id: String,
has_error: [:optional, TrueClass],
message: [:optional, String],
default_value: [:optional, String, Integer],
default_text: [:optional, String],
paginate: [:optional, TrueClass],
paginate_size: [:optional, Integer],
search: [:optional, TrueClass],
clear: [:optional, TrueClass],
placeholder: [:optional, String],
theme: [:optional, String],
required: [:optional, TrueClass],
})
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

<div class="
sage-dynamic-select
<%= "sage-select--error" if component.has_error %>
<%= component.generated_css_classes %>">
<% unless component.theme.present? && component.theme != 'sage' %>
<label class="sage-select__label" for="<%= component.id %>"><%= component.label || component.id %></label>
<% end %>
<select
class="sage-dynamic-select__data"
<%= component.generated_html_attributes.html_safe %>
name="<%= component.name %>"
id="<%= component.id %>"
tabindex="-1"
aria-hidden="true"
data-js-dynamic-select="true"
data-url=<%= component.url %>
data-placeholder="<%= component.placeholder || component.label || component.id %>"
<% if component.default_value.present? %>
data-default-value="<%= component.default_value %>"
<% end %>
<% if component.default_value.present? %>
data-default-text="<%= component.default_text %>"
<% end %>
<% if component.paginate.present? %>
data-paginate="<%= component.paginate %>"
data-paginate-size="<%= component.paginate_size || 25 %>"
<% end %>
<% if component.search.present? %>
data-search="<%= component.search %>"
<% end %>
<% if component.clear.present? %>
data-clear="<%= component.clear %>"
<% end %>
<% if component.theme.present? %>
data-theme="<%= component.theme %>"
<% else %>
data-theme="sage" %>
<% end %>
<%= 'required' if component.required.present? %>
>
</select>
<div class="sage-select__message"><%= component.message %></div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
$-dynamic-select-default-height: rem(45);
$-dynamic-select-default-padding: rem(4) sage-spacing(sm) 0;
$-dynamic-select-border-color: sage-color(gray, 400);
$-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);
$-dynamic-select-selected-padding: rem(12) sage-spacing(sm) 0;
$-dynamic-select-selected-tag-color: sage-color(primary, 400);
$-dynamic-select-selected-tag-background-color: sage-color(primary, 100);
$-dynamic-select-selected-tag-border-radius: sage-border(radius-x-large);
$-dynamic-select-selected-tag-padding: 0 sage-spacing(xs);
$-dynamic-select-selected-tag-height: rem(30);
$-dynamic-select-clear-font-weight: sage-font-weight(regular);
$-dynamic-select-open-arrow: rotate(180deg) scaleX(-1);

/* stylelint-disable selector-max-compound-selectors */

.sage-dynamic-select .sage-dynamic-select__data {
bottom: sage-spacing(xs);
left: 50%;
}

// empty state //
.sage-dynamic-select {
position: relative;
.select2-container--sage .sage-select__arrow::before {
top: rem(3);
}

.select2-container--sage .select2-dropdown--below {
margin-top: sage-spacing(xs);
}

.select2-container--sage .select2-selection--single.sage-select__field {
height: $-dynamic-select-default-height;
padding: $-dynamic-select-default-padding;
}

.select2-container--sage .select2-selection--single.sage-select__field .select2-selection__placeholder {
color: $-dynamic-select-placeholder-color;
}
.select2-container--sage .select2-selection--single.sage-select__field .select2-selection__clear {
float: right;
}
.select2-container--sage .select2-selection--single.sage-select__field .select2-selection__arrow b {
display: none;
}

// open state //
.select2-container--sage.select2-container--open .select2-selection--single.sage-select__field {
border-color: $-dynamic-select-color-success;
box-shadow: $-dynamic-select-border-box-shadow-size $-dynamic-select-color-success;
}

.select2-container--sage.select2-container--open .sage-select__arrow::before {
transform: $-dynamic-select-open-arrow;
}

.select2-container--sage.select2-container--open .sage-select__arrow::before,
.select2-container--sage:hover .sage-select__arrow::before {
color: $-dynamic-select-color-success;
}

// focused state //
.select2-container--sage.select2-container--focus .select2-selection--single.sage-select__field {
border-color: $-dynamic-select-border-color;
}
}

// selected state //
.sage-dynamic-select.sage-select--value-selected .select2-container--sage {
.sage-select__arrow::before {
top: rem(6);
}
.select2-selection--single.sage-select__field {
height: $-dynamic-select-selected-height;
padding: $-dynamic-select-selected-padding;
border-color: $-dynamic-select-border-color;
}
.select2-selection--single.sage-select__field .select2-selection__rendered {
@extend %t-sage-body-small-semi;
display: inline-flex;
flex-direction: row-reverse;
align-items: center;
height: $-dynamic-select-selected-tag-height;
padding: $-dynamic-select-selected-tag-padding;
color: $-dynamic-select-selected-tag-color;
background-color: $-dynamic-select-selected-tag-background-color;
border-radius: $-dynamic-select-selected-tag-border-radius;
}
.select2-selection--single.sage-select__field .select2-selection__rendered .select2-selection__clear {
font-weight: $-dynamic-select-clear-font-weight;
}
}

/* stylelint-enable selector-max-compound-selectors */
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ $-select-color-default: map-get($sage-field-colors, default);
$-select-color-error: map-get($sage-field-colors, error);
$-select-color-label-background: map-get($sage-field-colors, label-background);
$-select-color-success: map-get($sage-field-colors, success);
$-select-filled-top-padding: rem(6);
$-select-filled-top-padding: rem(4.4);
$-select-height: map-get($sage-field-configs, height);
$-select-padding-x: map-get($sage-field-configs, padding);
$-select-padding-label: map-get($sage-field-configs, padding-label);
Expand Down
1 change: 1 addition & 0 deletions packages/sage-assets/lib/stylesheets/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
@import "components/data_card";
@import "components/description";
@import "components/dropdown";
@import "components/dynamic_select";
@import "components/empty_state";
@import "components/expandable_card";
@import "components/feature_toggle";
Expand Down

0 comments on commit e38f1ca

Please sign in to comment.