rx / presenters Goto Github PK
View Code? Open in Web Editor NEWA ruby presentation DSL for describing Material Design user interfaces.
License: MIT License
A ruby presentation DSL for describing Material Design user interfaces.
License: MIT License
Describe the bug
When a pom attaches another that uses a plugin with Javascript the browser throws errors because the Javascript doesn't get included.
To Reproduce
Voom::Presenters.define(:some_pom) do
plugin :some_plugin_with_js
end
Voom::Presenters.define(:another) do
attach :some_pom
end
Render :another
in browser and there will be a Javascript undefined error. Currently including the plugin in :another
loads the files and clears the error, but this isn't ideal.
Expected behavior
The POM renders clean. JS from atached pom's plugins is included.
Text from a DB or other source with values that include markdown-like text will render in a markdown fashion. For example, text address[:ln2]
where address[:ln2] = "#1B"
renders 1B
as an <h1>
.
Describe the solution you'd like
I don't know if markdown should be the default. I suspect that making it not the default could introduce a ton of other problems with already created infrastructure though. A raw_text
component or an option on text
/body
would probably work.
The popup element of the date picker component cannot be easily closed. On iOS Safari (version 12), the popup can be dismissed only by clicking on another focusable element
Add support for any default text/formatting to be loaded from i18n json files.
As a developer, who is creating a form with a max length requirement for an input field, I would like the ability to pass in a maxlength
attribute when creating a text_field
.
Proposed Change
Component Class
require 'voom/presenters/dsl/components/input'
module Voom
module Presenters
module DSL
module Components
class TextField < Input
attr_reader :required, :full_width, :password, :auto_complete
def initialize(**attribs_, &block)
super(type: :text_field, **attribs_, &block)
@required = attribs.delete(:required){ false }
@full_width = attribs.delete(:full_width){ true }
@password = attribs.delete(:password){ false }
@maxlength = attribs.delete(:maxlength) { nil }
@auto_complete = validate_auto_complete(attribs.delete(:auto_complete) { :off })
label(attribs.delete(:label))if attribs.key?(:label)
value(attribs.delete(:value))if attribs.key?(:value)
expand!
end
def label(text=nil)
return @label if locked?
@label = text
end
def icon(icon=nil, **attribs, &block)
return @icon if locked?
@icon = Components::Icon.new(parent: self, icon: icon, position: attribs.delete(:position){:right},
**attribs, &block)
end
def value(value=nil)
return @value if locked?
@value = value
end
def pattern(pattern=nil)
return @pattern if locked?
@pattern = json_regexp(Regexp.new(pattern))
end
def hint(hint=nil)
return @hint if locked?
@hint = hint
end
def error(error=nil)
return @error if locked?
@error = error
end
private
def json_regexp(regexp)
str = regexp.inspect.
sub('\\A', '^').
sub('\\Z', '$').
sub('\\z', '$').
sub(/^\//, '').
sub(/\/[a-z]*$/, '').
gsub(/\(\?#.+\)/, '').
gsub(/\(\?-\w+:/, '(').
gsub(/\s/, '')
Regexp.new(str).source
end
def validate_auto_complete(value)
case value
when false, :disabled, 'disabled', 'off', nil
:off
when true, :enabled, 'enabled', 'on'
:on
else # :on, :off, client-specific values
value
end
end
end
end
end
end
end
Component HTML
<% if comp
leading_icon = comp.icon && comp.icon.position.select {|p| eq(p, :left)}.any?
trailing_icon = comp.icon && comp.icon.position.select {|p| eq(p, :right)}.any?
auto_complete = comp.auto_complete&.to_sym == :off ? 'extra-off' : comp.auto_complete
%>
<div id="<%= comp.id %>"
<% if comp.tag %>data-input-tag="<%= comp.tag %>"<% end %>
<% if comp.dirtyable %>data-dirtyable<% end %>
class="v-input v-text-field v-focusable mdc-text-field mdc-text-field--outlined
<%= 'mdc-text-field--with-leading-icon' if leading_icon %>
<%= 'mdc-text-field--with-trailing-icon' if trailing_icon %>
<%= 'mdc-text-field--disabled' if comp.disabled %>
<%= 'is-invalid is-dirty' if comp.error %>"
style="<%= 'width:100%' if comp.full_width %>">
<input id="<%= comp.id %>-input"
name="<%= comp.name %>"
type="<%= comp.password ? 'password' : 'text' %>"
value="<%= comp.value %>"
class="mdc-text-field__input"
aria-controls="<%= comp.id %>-input-helper-text"
<% if comp.disabled %>disabled<% end %>
<%= 'required' if comp.required %>
<%= 'invalid' if comp.error %>
<%= "pattern='#{comp.pattern}'" if comp.pattern %>
<%= "maxlength='#{comp.maxlength}'" if comp.maxlength %>
autocomplete="<%= auto_complete %>"
list="<%= comp.id %>-list"
<%= erb :"components/event", :locals => {comp: comp, events: comp.events, parent_id: "#{comp.id}-input"} %>>
<%= erb :"components/icon", :locals => {comp: comp.icon, class_name: 'mdc-text-field__icon', parent_id: "#{comp.id}-input"} %>
<div class="mdc-notched-outline">
<div class="mdc-notched-outline__leading"></div>
<div class="mdc-notched-outline__notch">
<label for="<%= comp.id %>-input" class="mdc-floating-label"><%= comp.label %></label>
</div>
<div class="mdc-notched-outline__trailing"></div>
</div>
<datalist id="<%= comp.id %>-list">
</datalist>
</div>
<% if comp.error || comp.hint %>
<p id="<%= comp.id %>-input-helper-text" class="mdc-text-field-helper-text mdc-text-field-helper-text--persistent mdc-text-field-helper-text--validation-msg" aria-hidden="true">
<%= comp.error || comp.hint %>
</p>
<% end %>
<%= erb :"components/tooltip", :locals => {comp: comp.tooltip, parent_id: comp.id} %>
<% end %>
If its applied to the form it is honored by chrome: Version 69.0.3497.100 (Official Build) (64-bit)
<form autocomplete='off'>
More info: https://stackoverflow.com/questions/15738259/disabling-chrome-autofill
Describe the bug
In a post event any components or plugins that provide a validate
function should be called, but they are not. Only the component that triggers the event has its validate function run.
Expected behavior
All input components included in a post event should be validated if they provide a validate
function.
Is your feature request related to a problem? Please describe.
Currently, links are only created via a block with
event :click do
loads :other_presenter
end
which is alright, but causes a problem in that, when rendered in the web client, each link is merely an <a>
tag with a link to javascript:void(0)
. This breaks the web for anyone who might want to open a link in a new tab, an incognito window, copy the URL, etc.
Describe the solution you'd like
loads
is important and needs to stay, but I'd like to see a link
or other noun/verb component implemented, such that I could do:
link to: :other_presenter do
icon :fa_cog, position: :left
body "My Link"
end
and have that render as an <a>
tag.
Would like the ability list one or more chips within a text input field. See here for an example:
https://material.io/archive/guidelines/components/chips.html#chips-usage
Example:
list do
items.each do |items|
line item.name do
actions do
button icon: :more_vert do
menu do
item 'Delete', icon: :delete do
end
end
end
end
end
end```
Think it has something to do with the position: fixed inside a list perhaps.
The rich text area component should be its own plugin.
The rich text area component:
The rich text area as a built-in component doesn't support points 3 and 4 above.
Describe the bug
Rich text areas with initial values report as dirty before any changes have been made.
To Reproduce
Steps to reproduce the behavior:
content do
rich_text_area do
value 'here is some default text'
end
button :cancel do
event :click do
prompt_if_dirty :some_dialog
# ...
end
end
end
prompt_if_dirty
checkExpected behavior
The prompt_if_dirty
check should not invoke :some_dialog
.
Desktop:
When you specify a pattern and error message for a text field the error message is always being displayed and then has a color change when the text_field fails the pattern match. I would expect that the message would remain hidden until the contents fail the patten match at which time the message would be displayed with appropriate error msg color.
Steps to Reproduce
Expected behavior
The label should be loaded.
Other
A similar but different problem can be seen in the presenters demo:
Desktop (please complete the following information):
Disable submitting a form while processing actions. Display a progress while waiting.
Describe the bug
When you land on a page with a text field that is pre-filled by the browser, its label stays in the "empty" position and is unreadable until it receives focus.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Fields with input should have readable labels along the top border.
Screenshots
Desktop (please complete the following information):
Describe the bug
If you have a button with an event :click
that does a POST and then loads another presenter/page, the button will become clickable immediately after the POST completes, which may not be desirable. The button should only be enabled after all action in the event block have completed
Additional context
See Geotix pivotal ticket #169553198
In the webclient checkbox/toggle controls don't post when in an off state.
All toggles should always post a name and value. The value should be off if no other value is provided.
Is your feature request related to a problem? Please describe.
Inside of the ExpansionPanel
component there is the ability to render text and secondary text elements. Each element is currently hard coded as semantic HTML as span
tags. It would be nice to simply render the respective Typography
component and pass in the local attributes it cares about.
Describe the solution you'd like
I'd like to either A) rebuild the typography component into multiple ones (H1, H2, H3, Span, etc) to support semantic HTML components or B) rebuild the typography component in the interim to render <span>
tags instead of <div>
elements.
Describe alternatives you've considered
I have simply just modified the ExpansionPanel
markup to support the attributes I care about
Additional context
N/A
The events loads, updates, posts, delete and replaces has been adding two parameters to the URL's. One happens in the URL creation by the url call in the dsl objects. (It delegates to the router.)
The second one is added by the client side javascript.
Fix this so that parameters are put on the url for loads, replaces and deletes
And add parameters to post body for updates and deletes.
Another related issues, a nil value will get posted back as a null string.
Posts and Updates should post key=
Loads, replaces and delete should add &key&
to the URL.
This ensures the presence of the key can have meaning, but the value will be nil. (And avoids fix-up code dealing with 'null' somewhere else.)
A form-field should not be a container component. The fact that it is a container to single input is unnecessary, confusing and is causing extra code to check for this case.
The MDC component should be initialized as part of the input component.
Use case: I'm using a chip to submit a name/value pair. The value I want to pass is a hash (or array). I expect that it will properly escape my ruby hash or array into query string that will come back into my rails controller or sinatra route params in the same format.
FWIW - A workaround is to json encode the values and decode on the way back in.
Automatic display of progress bars on posts/updates/deletes/loads.
The label element contained within toggle components is misaligned when embedded in an element smaller than 12 column-widths:
dialog width: '30rem' do
form do
switch name: :reset_password_email, checked: true, text: 'Send reset password email'
end
end
When contained within a column of size 12, the label lacks any leading space:
grid do
column size: 12 do
switch name: :reset_password_email, checked: true, text: 'Send reset password email'
end
end
Our current temporary date input field only supports US based dates.
This is issue a placeholder waiting for the release of the MDC Date/Time picker as outlined in the Material Design spec.
Describe the bug
The data-original-value
attribute for text area components (text area, rich text area) is not escaped correctly and can bleed out of its attribute value. This results in an incomplete attribute value, false positive for component dirty checks, and creation of attributes on the element named after the contents of the text area.
To Reproduce
Steps to reproduce the behavior:
"
) (e.g., most source code text areas in the Demo)data-original-value
attributeExpected behavior
The data-original-value
attribute should not bleed out and create extraneous attributes.
Create a container base class for components such as content, form, card, dialog, etc. and move common code into it.
If you have a list line with a click event and then an action on that line with a different event, multiple actions can be triggered. For example:
list do
things.each do |thing|
line do
text thing.name
event :click do
hide :this_content_block
show :some_other_block
end
actions do
switch name: :active, value: true, off_value: false, checked: thing.active do
event :change do
posts update_thing_path, thing_id: thing.id
end
end
end
end
end
end
Clicking the switch on a line will cause the post action to fire, but also the line's click event actions. Changing the switch's event to click
instead of change
makes it work as expected; the post fires, the hide/show does not.
If the MDC version of the slider component is initially rendered as hidden (inside a div with block: none) it does not initialize properly. A resize of the page will trigger the MDCSlider component to recalculate its layout and fixes the problem. I created a slider-render-issue branch that demonstrates the problem in demo/components.sliders.pom
grid do
column 6 do
headline 'Outside Form'
text_field
text_field
button 'Cancel', position: :right # BUG - filed as issue
button 'Continue', type: :raised, position: :right
end
end
This results in the cancel button being hidden by the continue button.
Expected: Inline elements floating to the right would appear side by side.
Describe the bug
The common mixin is not comprehensive enough to give consistent behavior across all types of containers. For example; a text field is valid inside a content
block, but not within a dialog
Expected behavior
Anything that can be used as a container - content
form
dialog
- should allow that same children and behave consistently.
They work if they are inside forms inside the dialog however.
All buttons rendered by the web client are missing the type
attribute, indicating to browsers that they're all submit
buttons. Per https://www.w3.org/TR/html5/forms.html#the-button-element:
The type attribute controls the behavior of the button when it is activated. [...]
The missing value default is the submit button state.
If the type attribute is in the submit button state, the element is specifically a submit button.
This causes a number of issues.
type="reset"
) cannot be renderedsubmit
) buttons (type="button"
) cannot be renderedCurrently dialogs are using MDL implementation in the webclient.
That does not work on safari correctly.
Question: Should we continue to use the form html element anymore?
Background: You can submit grouped input in a number of ways from the POM.
Content, dialog and card behavior does not use html forms.
One of the biggest issues is that nested forms on chrome (and possibly other browsers) are collapsed in the markup, the result is that the inner form tag is discarded.
To be more consistent, and not have special case for forms, we should eliminate the form behavior and alias the form POM keyword to content.
Other notes:
The current select all checkbox in a table header only selects all the checkboxes visible on the page. We need to add the functionality currently part of the selectable list, where you can toggle on/off selection of the entire results set across all pages.
Describe the bug
The web client's replaces
event (VReplaces
) does not work correctly in Edge 44 and earlier.
To Reproduce
Steps to reproduce the behavior:
If you got here it may not be what you think: ReferenceError: 'InputEvent' is not defined
Expected behavior
The Replaces button correctly replaces the target content area.
Desktop:
Additional context
Edge does not support InputEvent
: https://developer.mozilla.org/en-US/docs/Web/API/InputEvent#Browser_compatibility
If a form contains a <select>
with no <option>
elements, submitting the form yields a corresponding key-value pair with a string literal 'null'
value. Non-empty selects and empty non-select elements yield the empty string.
Example:
form do
select name: :select1 do
label 'Select1'
# first item selected by default:
some_array.each_with_index do |item, i|
option text: item, value: i
end
end
select name: :select2 do
label 'Select2'
# no options:
[].each_with_index do |item, i|
option text: item, value: i
end
end
button 'Submit' do
creates some_path, redirect: some_other_path
end
end
Submitting the above form yields:
select1: 0
select2: "null"
The current process for aggregating and displaying errors from server responses is not capable of handling deeply-nested error structures (e.g. nested Dry validation schemas, arrays).
Additionally, only client-side errors are visually associated with their failing element.
The current implementation yields the following behavior:
[object Object]
in the nearest error <div>
element.<div>
element instead of close to or within each error's associated element.<div>
element behavior) should be used only when an error cannot be associated with an element (e.g., errors describing a loss of network connectivity).I'm often frustrated when I make a link via a button
-> loads
action, or a list -> item in presenters but in the webclient, this basic link is rendered with an href of javascript:void(0)
or blank, or as an HTML button and I can't do some standard browser things like middle-click it and such.
I don't know if there's a simple fix for this. Basically anything that could take a click
event would need to be checkable and rendered differently if and only if the only click
action is a loads
. That part might not be too hard. But, there's a ton of CSS changes that could/would be involved in such an endeavor. Standard buttons currently render as the HTML button tag but these would need to be changed over to be a tags that look like buttons for this to work.
When using a plugin in a POM, changing files causes the plugin to stop functioning.
Voom::Presenters.define(:some_pom) do
plugin :some_plugin
# ...
end
Changing any file (including the POM itself) causes the autoloader to reload everything. Plugins seem to not be included in the reload sweep, however, and the POM fails to render at next page load:
NameError at /some/path
undefined local variable or method `some_plugin'
This can be worked around by require_depdency
'ing the plugin's main .rb
file and any files referenced therein:
Voom::Presenters.define(:some_pom) do
require_dependency 'voom/presenters/plugins/some_plugin.rb'
require_dependency 'voom/presenters/plugins/some_plugin/component.rb'
plugin :some_plugin
# no more NameError
end
All requests issued by the web client specify */*
as the value for the Accept
header. This value should be configurable (for POST requests, at least), allowing users to specify a preferred value.
You should be able to bind an event handler to a keydown event for a specific set of keys.
Examples - using enter key for submit, providing a keyboard friendly set of options.
Single key:
event :keypress, :enter do
# event handler code goes here
end
An array of keys:
event :keypress, :enter, :g do
# event handler code goes here
end
Having a modifier
event :keypress, :enter, {key: :g, modifiers: :ctrl} do
# event handler code goes here
end
Having multiple modifiers
event :keypress, :enter, {key: :g, modifiers: [:shift,:ctrl]} do
# event handler code goes here
end
Describe the bug
If an event is bound to element inside a component it may not get initialized as expected. For example, in the select component the events are bound to the select
element, when the component is initialized they are not found.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.