fron-ui 1.0.0rc2

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 (140) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rubocop.yml +38 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +7 -0
  7. data/.yardopts +8 -0
  8. data/Gemfile +8 -0
  9. data/Gemfile.lock +105 -0
  10. data/Rakefile +37 -0
  11. data/Readme.md +4 -0
  12. data/db.json +192 -0
  13. data/fron-ui.gemspec +21 -0
  14. data/lib/fron-ui.rb +1 -0
  15. data/lib/fron_ui.rb +5 -0
  16. data/lib/fron_ui/version.rb +7 -0
  17. data/opal/fron-ui/base.rb +49 -0
  18. data/opal/fron-ui/behaviors/action.rb +40 -0
  19. data/opal/fron-ui/behaviors/actions.rb +40 -0
  20. data/opal/fron-ui/behaviors/confirmation.rb +23 -0
  21. data/opal/fron-ui/behaviors/dropdown.rb +27 -0
  22. data/opal/fron-ui/behaviors/file.rb +48 -0
  23. data/opal/fron-ui/behaviors/intendable_children.rb +76 -0
  24. data/opal/fron-ui/behaviors/keydown.rb +31 -0
  25. data/opal/fron-ui/behaviors/loop.rb +41 -0
  26. data/opal/fron-ui/behaviors/render.rb +30 -0
  27. data/opal/fron-ui/behaviors/rest.rb +121 -0
  28. data/opal/fron-ui/behaviors/selectable_children.rb +67 -0
  29. data/opal/fron-ui/behaviors/serialize.rb +32 -0
  30. data/opal/fron-ui/behaviors/shortcuts.rb +35 -0
  31. data/opal/fron-ui/behaviors/state.rb +56 -0
  32. data/opal/fron-ui/behaviors/transition.rb +63 -0
  33. data/opal/fron-ui/components/action.rb +18 -0
  34. data/opal/fron-ui/components/box.rb +17 -0
  35. data/opal/fron-ui/components/button.rb +61 -0
  36. data/opal/fron-ui/components/calendar.rb +129 -0
  37. data/opal/fron-ui/components/checkbox.rb +57 -0
  38. data/opal/fron-ui/components/chooser.rb +246 -0
  39. data/opal/fron-ui/components/color_panel.rb +235 -0
  40. data/opal/fron-ui/components/color_picker.rb +111 -0
  41. data/opal/fron-ui/components/container.rb +61 -0
  42. data/opal/fron-ui/components/date_picker.rb +141 -0
  43. data/opal/fron-ui/components/drag.rb +76 -0
  44. data/opal/fron-ui/components/dropdown.rb +72 -0
  45. data/opal/fron-ui/components/icon.rb +29 -0
  46. data/opal/fron-ui/components/image.rb +77 -0
  47. data/opal/fron-ui/components/input.rb +30 -0
  48. data/opal/fron-ui/components/label.rb +9 -0
  49. data/opal/fron-ui/components/list.rb +34 -0
  50. data/opal/fron-ui/components/loader.rb +63 -0
  51. data/opal/fron-ui/components/modal.rb +0 -0
  52. data/opal/fron-ui/components/notifications.rb +73 -0
  53. data/opal/fron-ui/components/number.rb +202 -0
  54. data/opal/fron-ui/components/progress.rb +52 -0
  55. data/opal/fron-ui/components/slider.rb +47 -0
  56. data/opal/fron-ui/components/tabs.rb +149 -0
  57. data/opal/fron-ui/components/textarea.rb +13 -0
  58. data/opal/fron-ui/components/time.rb +65 -0
  59. data/opal/fron-ui/components/title.rb +34 -0
  60. data/opal/fron-ui/examples/blog/index.rb +289 -0
  61. data/opal/fron-ui/examples/comments/components/comment.rb +75 -0
  62. data/opal/fron-ui/examples/comments/components/comments.rb +93 -0
  63. data/opal/fron-ui/examples/comments/components/footer.rb +36 -0
  64. data/opal/fron-ui/examples/comments/components/header.rb +35 -0
  65. data/opal/fron-ui/examples/comments/components/list.rb +12 -0
  66. data/opal/fron-ui/examples/comments/index.rb +6 -0
  67. data/opal/fron-ui/examples/contacts/components/contacts.rb +100 -0
  68. data/opal/fron-ui/examples/contacts/components/details.rb +92 -0
  69. data/opal/fron-ui/examples/contacts/components/item.rb +46 -0
  70. data/opal/fron-ui/examples/contacts/components/list.rb +10 -0
  71. data/opal/fron-ui/examples/contacts/components/sidebar.rb +30 -0
  72. data/opal/fron-ui/examples/contacts/index.rb +6 -0
  73. data/opal/fron-ui/examples/editor/index.rb +164 -0
  74. data/opal/fron-ui/examples/kitchensink/index.rb +193 -0
  75. data/opal/fron-ui/examples/todos/components/item.rb +84 -0
  76. data/opal/fron-ui/examples/todos/components/options.rb +26 -0
  77. data/opal/fron-ui/examples/todos/components/todos.rb +145 -0
  78. data/opal/fron-ui/examples/todos/index.rb +6 -0
  79. data/opal/fron-ui/examples/webshop/index.rb +0 -0
  80. data/opal/fron-ui/fonts/ionicons.rb +2954 -0
  81. data/opal/fron-ui/fonts/open_sans.rb +19 -0
  82. data/opal/fron-ui/lib/collection.rb +138 -0
  83. data/opal/fron-ui/lib/date.rb +23 -0
  84. data/opal/fron-ui/lib/debounce.rb +14 -0
  85. data/opal/fron-ui/lib/image_loader.rb +13 -0
  86. data/opal/fron-ui/lib/lorem.rb +93 -0
  87. data/opal/fron-ui/lib/nil.rb +29 -0
  88. data/opal/fron-ui/lib/record.rb +23 -0
  89. data/opal/fron-ui/lib/state_serializer.rb +129 -0
  90. data/opal/fron-ui/lib/storage.rb +57 -0
  91. data/opal/fron-ui/spec/setup.rb +40 -0
  92. data/opal/fron-ui/ui.rb +40 -0
  93. data/opal/fron-ui/utils/theme_roller.rb +63 -0
  94. data/opal/fron-ui/vendor/autoprefixer.js +21114 -0
  95. data/opal/fron-ui/vendor/marked.js +1291 -0
  96. data/opal/fron-ui/vendor/md5.js +274 -0
  97. data/opal/fron-ui/vendor/moment.js +3083 -0
  98. data/opal/fron-ui/vendor/uuid.js +92 -0
  99. data/opal/fron_ui.rb +13 -0
  100. data/spec/behaviors/action_spec.rb +34 -0
  101. data/spec/behaviors/actions_spec.rb +38 -0
  102. data/spec/behaviors/confirmation_spec.rb +23 -0
  103. data/spec/behaviors/dropdown_spec.rb +32 -0
  104. data/spec/behaviors/render_spec.rb +20 -0
  105. data/spec/behaviors/rest_spec.rb +70 -0
  106. data/spec/behaviors/selectable_children_spec.rb +40 -0
  107. data/spec/behaviors/serialize_spec.rb +34 -0
  108. data/spec/components/action_spec.rb +7 -0
  109. data/spec/components/base_spec.rb +19 -0
  110. data/spec/components/box_spec.rb +7 -0
  111. data/spec/components/button_spec.rb +9 -0
  112. data/spec/components/calendar_spec.rb +58 -0
  113. data/spec/components/checkbox_spec.rb +20 -0
  114. data/spec/components/chooser_spec.rb +75 -0
  115. data/spec/components/color_panel_spec.rb +49 -0
  116. data/spec/components/color_picker_spec.rb +41 -0
  117. data/spec/components/container_spec.rb +23 -0
  118. data/spec/components/date_picker_spec.rb +71 -0
  119. data/spec/components/drag_spec.rb +20 -0
  120. data/spec/components/dropdown_spec.rb +33 -0
  121. data/spec/components/image_spec.rb +33 -0
  122. data/spec/components/input_spec.rb +8 -0
  123. data/spec/components/list_spec.rb +10 -0
  124. data/spec/components/loader_spec.rb +9 -0
  125. data/spec/components/notifications_spec.rb +17 -0
  126. data/spec/components/number_spec.rb +64 -0
  127. data/spec/components/progress_spec.rb +23 -0
  128. data/spec/components/slider_spec.rb +25 -0
  129. data/spec/components/tabs_spec.rb +50 -0
  130. data/spec/components/textarea_spec.rb +7 -0
  131. data/spec/components/time_spec.rb +37 -0
  132. data/spec/components/title_spec.rb +11 -0
  133. data/spec/examples/comments_spec.rb +72 -0
  134. data/spec/examples/todos_spec.rb +39 -0
  135. data/spec/lib/collection_spec.rb +38 -0
  136. data/spec/lib/lorem_spec.rb +55 -0
  137. data/spec/lib/state_serializer_spec.rb +58 -0
  138. data/spec/lib/storage_spec.rb +39 -0
  139. data/spec/spec_helper.rb +1 -0
  140. metadata +223 -0
@@ -0,0 +1,111 @@
1
+ require 'fron-ui/components/input'
2
+ require 'fron-ui/components/dropdown'
3
+ require 'fron-ui/components/color_panel'
4
+
5
+ module UI
6
+ # Component for selecting colors by a color picker
7
+ # or just typing.
8
+ #
9
+ # Features:
10
+ # * Typing a CSS color (hex or named) and
11
+ # pressing enter will update the color panel.
12
+ # * Has a rectange for showing the selected color.
13
+ #
14
+ # @author Gusztáv Szikszai
15
+ # @since 0.1.0
16
+ class ColorPicker < Base
17
+ include UI::Behaviors::Dropdown
18
+
19
+ extend Forwardable
20
+
21
+ tag 'ui-color-picker'
22
+
23
+ component :input, UI::Input, spellcheck: false
24
+ component :div, 'div'
25
+
26
+ component :dropdown, UI::Dropdown do
27
+ component :color_panel, UI::ColorPanel
28
+ end
29
+
30
+ style display: 'inline-block',
31
+ position: :relative,
32
+ div: { boxShadow: '0 0 1px 1px rgba(0,0,0,0.2) inset',
33
+ borderRadius: -> { theme.border_radius.em },
34
+ pointerEvents: :none,
35
+ position: :absolute,
36
+ bottom: 0.3.em,
37
+ right: 0.3.em,
38
+ top: 0.3.em,
39
+ width: 2.em },
40
+ input: { paddingRight: -> { (theme.size * 1.25).em },
41
+ boxSizing: 'border-box',
42
+ width: '100%' }
43
+
44
+ on :change, :input, :update_dropdown
45
+ on :change, 'ui-color-wheel', :update_input
46
+ on :change, 'ui-color-wheel, input', :delegate_change
47
+
48
+ def_delegators :input, :value
49
+ def_delegators :dropdown, :color_panel
50
+
51
+ dropdown :input, :dropdown
52
+
53
+ # Delegates the change event
54
+ # so the target would be the picker
55
+ # not the color panel
56
+ #
57
+ # @param event [DOM::Event] The event
58
+ def delegate_change(event)
59
+ event.stop
60
+ trigger :change
61
+ end
62
+
63
+ # Initializes the component:
64
+ #
65
+ # * When the input gets the focus
66
+ # update the dropdown.
67
+ # * Set default value to **white**
68
+ def initialize
69
+ super
70
+ @input.on(:focus) { update_dropdown }
71
+ @input.value = '#FFFFFF'
72
+ end
73
+
74
+ # Sets the value of the component
75
+ #
76
+ # @param value [String] The CSS color (hex or named)
77
+ def value=(value)
78
+ return if @input.value == value
79
+ @input.value = value
80
+ update_dropdown
81
+ trigger :change
82
+ end
83
+
84
+ private
85
+
86
+ # Updates the dropdown with the
87
+ # inputs value:
88
+ #
89
+ # * If the color is invalid update the input
90
+ # * Alwas render color of the rectange
91
+ def update_dropdown
92
+ color_panel.color = @input.value
93
+ rescue
94
+ update_input
95
+ ensure
96
+ render
97
+ end
98
+
99
+ # Update the value of the input
100
+ # from the color panel.
101
+ def update_input
102
+ @input.value = color_panel.to_css
103
+ render
104
+ end
105
+
106
+ # Renders the rectange
107
+ def render
108
+ @div.style.background = color_panel.to_css
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,61 @@
1
+ module UI
2
+ # Component for layout out children either
3
+ # vertically or horizontally using flexbox.
4
+ #
5
+ # Attributes:
6
+ # * *direction*:
7
+ # * *column* - lays out chilren vertically
8
+ # * *row* (default) - lays out children horizontally
9
+ # * *compact*:
10
+ # * *true* - no spacing between the children
11
+ # * *false* (default) - there is spacing between the children
12
+ #
13
+ # @example
14
+ # component :box, UI::Container, compact: true, direction: :column
15
+ #
16
+ # @author Gusztáv Szikszai
17
+ # @since 0.1.0
18
+ class Container < Base
19
+ tag 'ui-container'
20
+
21
+ style display: :flex,
22
+ fontFamily: -> { theme.font_family },
23
+ '&[direction=column]' => {
24
+ flexDirection: :column,
25
+ '&:not([compact]) > * + *' => {
26
+ marginTop: -> { theme.spacing.em }
27
+ }
28
+ },
29
+ '&[align=center]' => {
30
+ justifyContent: 'center'
31
+ },
32
+ '&[align=end]' => {
33
+ justifyContent: 'flex-end'
34
+ },
35
+ '&[direction=row]:not([compact]) > * + *' => {
36
+ marginLeft: -> { theme.spacing.em }
37
+ }
38
+
39
+ attribute_accessor :direction
40
+ attribute_accessor :align
41
+
42
+ # Initializes the container by setting
43
+ # default value for direction to column.
44
+ def initialize
45
+ super
46
+ self[:direction] ||= :column
47
+ end
48
+
49
+ # Sets / removes the compact attribute
50
+ # based on the value.
51
+ #
52
+ # @param value [Boolean] The value
53
+ def compact=(value)
54
+ if !value
55
+ remove_attribute :compact
56
+ else
57
+ self[:compact] = ''
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,141 @@
1
+ require 'fron-ui/components/input'
2
+ require 'fron-ui/components/icon'
3
+ require 'fron-ui/components/dropdown'
4
+ require 'fron-ui/components/calendar'
5
+
6
+ module UI
7
+ # Component for selecting a date
8
+ #
9
+ # Features:
10
+ # * Input field for manual input
11
+ # * Dropdown with calendar for date selection
12
+ # * Selected date is highlighted
13
+ #
14
+ # @attr_reader [Date] value The value of the component
15
+ #
16
+ # @author Gusztáv Szikszai
17
+ # @since 0.1.0
18
+ class DatePicker < Base
19
+ include UI::Behaviors::Keydown
20
+ include UI::Behaviors::Dropdown
21
+ extend Forwardable
22
+
23
+ attr_reader :value
24
+
25
+ tag 'ui-date-picker'
26
+
27
+ style color: -> { readable_color colors.input },
28
+ display: 'inline-block',
29
+ position: :relative,
30
+ '> ui-icon' => { width: -> { theme.size.em },
31
+ position: :absolute,
32
+ fontSize: 1.2.em,
33
+ bottom: 0,
34
+ right: 0,
35
+ top: 0 },
36
+ input: { paddingRight: -> { (theme.size * 1.25).em },
37
+ boxSizing: 'border-box',
38
+ width: '100%' },
39
+ 'table td[date]' => { cursor: :pointer,
40
+ '&:hover' => { color: -> { readable_color(colors.primary) },
41
+ background: -> { colors.primary },
42
+ fontWeight: 600 } },
43
+ 'table td[date].selected' => { color: -> { readable_color(colors.focus) },
44
+ background: -> { colors.focus },
45
+ fontWeight: 600 }
46
+
47
+ component :input, UI::Input
48
+ component :icon, UI::Icon, glyph: :calendar
49
+
50
+ component :dropdown, UI::Dropdown do
51
+ component :calendar, UI::Calendar
52
+ end
53
+
54
+ def_delegators :input, :active?, :focus, :blur
55
+
56
+ on :click, 'td[date]', :select
57
+ on :change, 'input', :changed
58
+ on :rendered, :render
59
+
60
+ keydown :down, :next
61
+ keydown :up, :prev
62
+
63
+ dropdown :input, :dropdown
64
+
65
+ # Initialize the component by
66
+ # setting the default value for today.
67
+ def initialize
68
+ super
69
+ @input.on(:focus) { render }
70
+ @dropdown.on :mousedown, &:prevent_default
71
+ self.value = Date.today
72
+ end
73
+
74
+ # Selects the next date, if shift is down
75
+ # it select the same date in the next month,
76
+ #
77
+ # @param event [DOM::Event] The event
78
+ def next(event)
79
+ self.value = if event.shift?
80
+ @value.next_month
81
+ else
82
+ @value + 1
83
+ end
84
+ end
85
+
86
+ # Selects the previous date, if shift is down
87
+ # it select the same date in the previous month,
88
+ #
89
+ # @param event [DOM::Event] The event
90
+ def prev(event)
91
+ self.value = if event.shift?
92
+ @value.prev_month
93
+ else
94
+ @value - 1
95
+ end
96
+ end
97
+
98
+ # Sets the value of the field
99
+ #
100
+ # @param date [Date] The date
101
+ def value=(date)
102
+ date = parse_date(date)
103
+ raise "Supplied value '#{date}' is not a date or cound't be coerced into one!" unless date.is_a?(Date)
104
+ changed = @value != date
105
+ @value = date
106
+ @input.value = @value.strftime
107
+ @dropdown.calendar.render @value
108
+ trigger :change if changed
109
+ end
110
+
111
+ def parse_date(raw)
112
+ Date.parse(raw)
113
+ rescue
114
+ raw
115
+ end
116
+
117
+ # Selects the clicked td
118
+ #
119
+ # @param event [DOM::Event] The event
120
+ def select(event)
121
+ self.value = Date.parse(event.target[:date])
122
+ end
123
+
124
+ # Updates the value after the change
125
+ # of the input, if it's a wrong date
126
+ # it sets it for today.
127
+ def changed
128
+ self.value = Date.parse(@input.value)
129
+ rescue
130
+ self.value = Date.today
131
+ warn 'Wrong date input!'
132
+ end
133
+
134
+ # Renders the component
135
+ def render
136
+ cell = @dropdown.find("td[date='#{value}']")
137
+ return unless cell
138
+ cell.add_class :selected
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,76 @@
1
+ module UI
2
+ # Base component for handling drags.
3
+ #
4
+ # @see UI::ColorPanel
5
+ # @see UI::Slider
6
+ #
7
+ # @attr value_x [Float] The value of the x axis (0..1)
8
+ # @attr value_y [Float] The value of the y axis (0..1)
9
+ # @attr vertical [Boolean] Whether or not to allow vertical drag
10
+ # @attr horizontal [Boolean] Whether or not to allow horizontal drag
11
+ # @attr_reader drag [Fron::Drag] The drag instance
12
+ #
13
+ # @author Gusztáv Szikszai
14
+ # @since 0.1.0
15
+ # @abstract
16
+ class Drag < Base
17
+ tag 'ui-drag'
18
+
19
+ attr_accessor :vertical, :horizontal
20
+ attr_reader :drag
21
+
22
+ component :handle, 'ui-drag-handle'
23
+
24
+ style background: -> { colors.input },
25
+ display: 'inline-block',
26
+ position: :relative,
27
+ 'ui-drag-handle' => {
28
+ background: -> { rgba(readable_color(colors.input), 0.5) },
29
+ transform: 'translateX(-50%) translateY(-50%)',
30
+ pointerEvents: :none,
31
+ position: :absolute,
32
+ borderRadius: '50%',
33
+ height: 1.em,
34
+ width: 1.em
35
+ }
36
+
37
+ # Axes for the drag
38
+ AXES = {
39
+ horizontal: { coord: :x, style: :left, side: :width },
40
+ vertical: { coord: :y, style: :top, side: :height }
41
+ }
42
+
43
+ # Initializes the component
44
+ def initialize
45
+ super
46
+ AXES.keys.each { |axis| send("#{axis}=", true) }
47
+
48
+ @drag = Fron::Drag.new self, 0
49
+ @drag.on(:move) { |position| on_drag_move position }
50
+ end
51
+
52
+ # Moves the handle from the position in each axis
53
+ #
54
+ # @param position [Fron::Point] The point
55
+ def on_drag_move(position)
56
+ point = position - Fron::Point.new(left, top)
57
+
58
+ AXES.each do |key, axis|
59
+ next unless send(key)
60
+ @handle.style[axis[:style]] = point.send(axis[:coord]).clamp(0, send(axis[:side])).px
61
+ end
62
+
63
+ trigger 'change'
64
+ end
65
+
66
+ AXES.values.each do |axis|
67
+ define_method "value_#{axis[:coord]}" do
68
+ @handle.style.send(axis[:style]).to_i / send(axis[:side])
69
+ end
70
+
71
+ define_method "value_#{axis[:coord]}=" do |position|
72
+ @handle.style[axis[:style]] = (position.clamp(0, 1) * send(axis[:side])).px
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,72 @@
1
+ require 'fron-ui/components/container'
2
+
3
+ module UI
4
+ # Component for handling open / closed state
5
+ # and stop events when clicking inside the
6
+ # component to prevent closing.
7
+ #
8
+ # @author Gusztáv Szikszai
9
+ # @since 0.1.0
10
+ class Dropdown < Container
11
+ include UI::Behaviors::Transition
12
+
13
+ tag 'ui-dropdown'
14
+
15
+ style boxShadow: '0 0.3em 0.625em -0.3em rgba(0,0,0,0.75)',
16
+ transition: 'opacity 320ms, transform 320ms',
17
+ borderRadius: -> { theme.border_radius.em },
18
+ background: -> { colors.input },
19
+ pointerEvents: :none,
20
+ position: :absolute,
21
+ display: :none,
22
+ zIndex: 100,
23
+ '&.open' => { display: :block, pointerEvents: :auto },
24
+ '&[vertical=top]' => { marginBottom: -> { (theme.spacing / 2).em },
25
+ bottom: '100%' },
26
+ '&[vertical=bottom]' => { marginTop: -> { (theme.spacing / 2).em },
27
+ top: '100%' },
28
+ '&[horizontal=left]' => { right: 0 },
29
+ '&[horizontal=right]' => { left: 0 }
30
+
31
+ transition :show, duration: '320ms',
32
+ frames: { '0%' => { opacity: 0, transform: 'translateY(0.5em)' },
33
+ '100%' => { opacity: 1, transform: 'translateY(0)' } }
34
+
35
+ transition :hide, duration: '320ms',
36
+ frames: { '0%' => { opacity: 1, transform: 'translateY(0)' },
37
+ '100%' => { opacity: 0, transform: 'translateY(0.5em)' } }
38
+
39
+ # Opens the component:
40
+ #
41
+ # * adds the *open* class
42
+ # * sets the *position* attribute to either top or bottom depending
43
+ # where is more space in the screen
44
+ def open
45
+ self[:vertical] = position?(:top, :scroll_y, :innerHeight) ? :top : :bottom
46
+ self[:horizontal] = position?(:left, :scroll_x, :innerWidth) ? :left : :right
47
+ add_class 'open'
48
+ transition! :show
49
+ end
50
+
51
+ # Closes the component
52
+ def close
53
+ transition! :hide do
54
+ remove_class 'open'
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # Returns which side to display the dropdown
61
+ # to based on parameters.
62
+ #
63
+ # @param style [Symbol] Which style to use
64
+ # @param scroll [Symbol] Which scroll position to use
65
+ # @param size [Symbol] Which window size to use
66
+ #
67
+ # @return [Bollean] True or False
68
+ def position?(style, scroll, size)
69
+ parent && (parent.send(style) - DOM::Window.send(scroll)) > `window[#{size}] / 2`
70
+ end
71
+ end
72
+ end