docks_theme_api 1.0.2

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 (237) hide show
  1. checksums.yaml +15 -0
  2. data/.babelrc +4 -0
  3. data/.editorconfig +8 -0
  4. data/.eslintrc +115 -0
  5. data/.gitignore +24 -0
  6. data/.rubocop.yml +20 -0
  7. data/.travis.yml +16 -0
  8. data/Gemfile +4 -0
  9. data/README.md +5 -0
  10. data/Rakefile +3 -0
  11. data/assets/images/icons.svg +63 -0
  12. data/assets/scripts/coffeescript/pattern_library_helpers.coffee +8 -0
  13. data/assets/scripts/javascript/pattern_library_helpers.js +11 -0
  14. data/assets/scripts/pattern_library.js +10380 -0
  15. data/assets/scripts/pattern_library_demo.js +0 -0
  16. data/assets/styles/less/pattern-library-helpers.less +103 -0
  17. data/assets/styles/pattern-library-demo.css +1882 -0
  18. data/assets/styles/pattern-library.css +1882 -0
  19. data/assets/styles/sass/pattern-library-helpers.sass +90 -0
  20. data/assets/styles/scss/pattern-library-helpers.scss +99 -0
  21. data/assets/styles/stylus/pattern-library-helpers.styl +90 -0
  22. data/assets/templates/erb/demo.erb +26 -0
  23. data/assets/templates/erb/layouts/demo.erb +17 -0
  24. data/assets/templates/erb/layouts/pattern.erb +76 -0
  25. data/assets/templates/erb/partials/sidebar.erb +124 -0
  26. data/assets/templates/erb/partials/symbols/class.erb +1 -0
  27. data/assets/templates/erb/partials/symbols/demo.erb +40 -0
  28. data/assets/templates/erb/partials/symbols/factory.erb +70 -0
  29. data/assets/templates/erb/partials/symbols/function.erb +103 -0
  30. data/assets/templates/erb/partials/symbols/mixin.erb +62 -0
  31. data/assets/templates/erb/partials/symbols/variable.erb +59 -0
  32. data/assets/templates/erb/pattern.erb +102 -0
  33. data/assets/templates/haml/demo.haml +14 -0
  34. data/assets/templates/haml/layouts/demo.haml +6 -0
  35. data/assets/templates/haml/layouts/pattern.haml +38 -0
  36. data/assets/templates/haml/partials/sidebar.haml +68 -0
  37. data/assets/templates/haml/partials/symbols/class.haml +1 -0
  38. data/assets/templates/haml/partials/symbols/demo.haml +23 -0
  39. data/assets/templates/haml/partials/symbols/factory.haml +38 -0
  40. data/assets/templates/haml/partials/symbols/function.haml +54 -0
  41. data/assets/templates/haml/partials/symbols/mixin.haml +31 -0
  42. data/assets/templates/haml/partials/symbols/variable.haml +22 -0
  43. data/assets/templates/haml/pattern.haml +54 -0
  44. data/assets/templates/slim/demo.slim +24 -0
  45. data/assets/templates/slim/layouts/demo.slim +5 -0
  46. data/assets/templates/slim/layouts/pattern.slim +48 -0
  47. data/assets/templates/slim/partials/sidebar.slim +112 -0
  48. data/assets/templates/slim/partials/symbols/class.slim +1 -0
  49. data/assets/templates/slim/partials/symbols/demo.slim +30 -0
  50. data/assets/templates/slim/partials/symbols/factory.slim +57 -0
  51. data/assets/templates/slim/partials/symbols/function.slim +81 -0
  52. data/assets/templates/slim/partials/symbols/mixin.slim +45 -0
  53. data/assets/templates/slim/partials/symbols/variable.slim +35 -0
  54. data/assets/templates/slim/pattern.slim +63 -0
  55. data/docks_config.rb +32 -0
  56. data/docks_theme_api.gemspec +37 -0
  57. data/gulpfile.js +88 -0
  58. data/karma.conf.js +6 -0
  59. data/lib/docks_theme_api/components/base_component.rb +99 -0
  60. data/lib/docks_theme_api/components/code_block_component.rb +10 -0
  61. data/lib/docks_theme_api/components/popover_component.rb +15 -0
  62. data/lib/docks_theme_api/components/table_component.rb +34 -0
  63. data/lib/docks_theme_api/components/tablist_component.rb +11 -0
  64. data/lib/docks_theme_api/components.rb +21 -0
  65. data/lib/docks_theme_api/helpers/ui_helper.rb +69 -0
  66. data/lib/docks_theme_api/theme.rb +21 -0
  67. data/lib/docks_theme_api.rb +1 -0
  68. data/package.json +60 -0
  69. data/source/behaviors/filterable/filterable.coffee +353 -0
  70. data/source/behaviors/filterable/filterable.js +0 -0
  71. data/source/behaviors/filterable/filterable.scss +34 -0
  72. data/source/behaviors/filterable/package.json +3 -0
  73. data/source/behaviors/index.js +0 -0
  74. data/source/components/avatar/avatar.erb +20 -0
  75. data/source/components/avatar/avatar.js +142 -0
  76. data/source/components/avatar/avatar.scss +200 -0
  77. data/source/components/avatar/avatar_container.erb +13 -0
  78. data/source/components/avatar/package.json +3 -0
  79. data/source/components/avatar/spec/avatar_spec.js +81 -0
  80. data/source/components/badge/badge.scss +158 -0
  81. data/source/components/button/button.scss +213 -0
  82. data/source/components/card/card.scss +32 -0
  83. data/source/components/code_block/code-block.scss +353 -0
  84. data/source/components/code_block/code_block.erb +95 -0
  85. data/source/components/code_block/code_block.js +444 -0
  86. data/source/components/code_block/package.json +3 -0
  87. data/source/components/code_block/spec/code_block_spec.js +10 -0
  88. data/source/components/demo/demo.js +244 -0
  89. data/source/components/demo/demo.scss +90 -0
  90. data/source/components/demo/package.json +3 -0
  91. data/source/components/exploded/exploded.erb +25 -0
  92. data/source/components/exploded/exploded.js +694 -0
  93. data/source/components/exploded/exploded.scss +166 -0
  94. data/source/components/exploded/package.json +3 -0
  95. data/source/components/field/field.js +24 -0
  96. data/source/components/field/field.scss +101 -0
  97. data/source/components/field/package.json +3 -0
  98. data/source/components/header/header.scss +33 -0
  99. data/source/components/iframe/iframe.erb +12 -0
  100. data/source/components/iframe/iframe.js +381 -0
  101. data/source/components/iframe/package.json +3 -0
  102. data/source/components/index.js +37 -0
  103. data/source/components/inline_group/inline-group.scss +14 -0
  104. data/source/components/internal_link/internal_link.js +49 -0
  105. data/source/components/internal_link/package.json +3 -0
  106. data/source/components/list/list.scss +230 -0
  107. data/source/components/modal/modal.coffee +84 -0
  108. data/source/components/modal/modal.erb +19 -0
  109. data/source/components/modal/modal.js +0 -0
  110. data/source/components/modal/modal.scss +57 -0
  111. data/source/components/modal/package.json +3 -0
  112. data/source/components/notice/notice.scss +48 -0
  113. data/source/components/popover/package.json +3 -0
  114. data/source/components/popover/popover.coffee +562 -0
  115. data/source/components/popover/popover.erb +21 -0
  116. data/source/components/popover/popover.js +0 -0
  117. data/source/components/popover/popover.scss +139 -0
  118. data/source/components/range/range.scss +78 -0
  119. data/source/components/resizable/package.json +3 -0
  120. data/source/components/resizable/resizable.erb +30 -0
  121. data/source/components/resizable/resizable.js +250 -0
  122. data/source/components/resizable/resizable.scss +245 -0
  123. data/source/components/resizable/size_buttons.js +249 -0
  124. data/source/components/scroll_container/package.json +3 -0
  125. data/source/components/scroll_container/scroll-container.scss +4 -0
  126. data/source/components/scroll_container/scroll_container.js +24 -0
  127. data/source/components/section/section.scss +99 -0
  128. data/source/components/select/package.json +3 -0
  129. data/source/components/select/select.erb +21 -0
  130. data/source/components/select/select.js +35 -0
  131. data/source/components/select/select.scss +163 -0
  132. data/source/components/table/package.json +3 -0
  133. data/source/components/table/table.erb +16 -0
  134. data/source/components/table/table.js +351 -0
  135. data/source/components/table/table.scss +236 -0
  136. data/source/components/tablist/package.json +3 -0
  137. data/source/components/tablist/tablist.erb +13 -0
  138. data/source/components/tablist/tablist.js +246 -0
  139. data/source/components/tablist/tablist.scss +191 -0
  140. data/source/components/tablist/tablist_panel.erb +14 -0
  141. data/source/components/tablist/tablist_tab.erb +20 -0
  142. data/source/components/toggle/package.json +3 -0
  143. data/source/components/toggle/toggle.erb +11 -0
  144. data/source/components/toggle/toggle.js +211 -0
  145. data/source/components/toggle/toggle_container.erb +30 -0
  146. data/source/components/vertical_spacer/vertical-spacer.scss +3 -0
  147. data/source/components/vertical_stack/vertical-stack.scss +19 -0
  148. data/source/components/xray/package.json +3 -0
  149. data/source/components/xray/xray.erb +50 -0
  150. data/source/components/xray/xray.js +123 -0
  151. data/source/components/xray/xray.scss +79 -0
  152. data/source/foundation/app/app.js +15 -0
  153. data/source/foundation/app/package.json +3 -0
  154. data/source/pattern-library-demo.scss +13 -0
  155. data/source/pattern-library.scss +13 -0
  156. data/source/pattern_library.js +8 -0
  157. data/source/pattern_library_demo.js +8 -0
  158. data/source/structures/index.js +11 -0
  159. data/source/structures/sidebar/package.json +3 -0
  160. data/source/structures/sidebar/sidebar.js +69 -0
  161. data/source/structures/sidebar/sidebar.scss +79 -0
  162. data/source/utilities/builder/builder.js +138 -0
  163. data/source/utilities/builder/package.json +3 -0
  164. data/source/utilities/client/client.js +7 -0
  165. data/source/utilities/client/package.json +3 -0
  166. data/source/utilities/colors/colors.scss +112 -0
  167. data/source/utilities/defaults/defaults.scss +38 -0
  168. data/source/utilities/dom_cache/dom_cache.js +24 -0
  169. data/source/utilities/dom_cache/package.json +3 -0
  170. data/source/utilities/events/events.js +25 -0
  171. data/source/utilities/events/package.json +3 -0
  172. data/source/utilities/font_sizes/font-sizes.scss +85 -0
  173. data/source/utilities/foundation/a11y.scss +10 -0
  174. data/source/utilities/foundation/base.scss +29 -0
  175. data/source/utilities/foundation/icon.scss +114 -0
  176. data/source/utilities/foundation/layout.scss +67 -0
  177. data/source/utilities/foundation/page.scss +39 -0
  178. data/source/utilities/foundation/type.scss +208 -0
  179. data/source/utilities/functions/functions.scss +127 -0
  180. data/source/utilities/keycodes/keycodes.js +23 -0
  181. data/source/utilities/keycodes/package.json +3 -0
  182. data/source/utilities/markup/markup.js +90 -0
  183. data/source/utilities/markup/package.json +3 -0
  184. data/source/utilities/media/media.scss +172 -0
  185. data/source/utilities/mixins/mixins.scss +89 -0
  186. data/source/utilities/naming_convention/naming_convention.js +3 -0
  187. data/source/utilities/naming_convention/package.json +3 -0
  188. data/source/utilities/numbers/numbers.js +14 -0
  189. data/source/utilities/numbers/package.json +3 -0
  190. data/source/utilities/painting/package.json +3 -0
  191. data/source/utilities/painting/painting.js +7 -0
  192. data/source/utilities/pattern/package.json +3 -0
  193. data/source/utilities/pattern/pattern.js +50 -0
  194. data/source/utilities/query_string/package.json +3 -0
  195. data/source/utilities/query_string/query_string.js +24 -0
  196. data/source/utilities/template/package.json +3 -0
  197. data/source/utilities/template/template.js +10 -0
  198. data/source/utilities/text_range/package.json +3 -0
  199. data/source/utilities/text_range/text_range.js +30 -0
  200. data/source/utilities/ui_events/package.json +3 -0
  201. data/source/utilities/ui_events/ui_events.js +85 -0
  202. data/source/utilities/variables/variables.scss +18 -0
  203. data/source/utilities/z_indexes/z-indexes.scss +88 -0
  204. data/source/vendor/array_includes.js +28 -0
  205. data/source/vendor/highlight.js +1142 -0
  206. data/source/vendor/index.js +1 -0
  207. data/source/vendor/matrix.js +399 -0
  208. data/source/vendor/query_string.js +66 -0
  209. data/spec/assets/.eslintrc +9 -0
  210. data/spec/assets/spec_fixture.js +33 -0
  211. data/spec/assets/spec_helper.js +19 -0
  212. data/spec/lib/components/base_component_spec.rb +156 -0
  213. data/spec/lib/components_spec.rb +30 -0
  214. data/spec/lib/helpers/ui_helper_spec.rb +62 -0
  215. data/spec/lib/theme_spec.rb +25 -0
  216. data/spec/spec_helper.rb +15 -0
  217. data/tasks/gulp/.eslintrc +6 -0
  218. data/tasks/gulp/browser_sync.js +8 -0
  219. data/tasks/gulp/code_quality/scripts.js +10 -0
  220. data/tasks/gulp/config/index.js +116 -0
  221. data/tasks/gulp/minify/scripts.js +13 -0
  222. data/tasks/gulp/minify/styles.js +13 -0
  223. data/tasks/gulp/pattern_library/index.js +5 -0
  224. data/tasks/gulp/pattern_library/scripts.js +10 -0
  225. data/tasks/gulp/pattern_library/styles.js +10 -0
  226. data/tasks/gulp/scripts.js +8 -0
  227. data/tasks/gulp/spec/scripts.js +11 -0
  228. data/tasks/gulp/styles.js +17 -0
  229. data/tasks/gulp/utilities/babel/relative_require.js +22 -0
  230. data/tasks/gulp/utilities/babel/spec_helper.js +20 -0
  231. data/tasks/gulp/utilities/browserify_bundler.js +22 -0
  232. data/tasks/gulp/utilities/handle_errors.js +13 -0
  233. data/tasks/gulp/watch.js +9 -0
  234. data/tasks/rake/rspec.rake +7 -0
  235. data/tasks/rake/rubocop.rake +8 -0
  236. data/tasks/rake/templates.rake +50 -0
  237. metadata +470 -0
@@ -0,0 +1,562 @@
1
+ BASE_CLASS = "popover"
2
+
3
+ CLASSES =
4
+ BASE: BASE_CLASS
5
+ CONTAINER: "#{BASE_CLASS}__container"
6
+ CONTENT_WRAPPER: "#{BASE_CLASS}__content-wrapper"
7
+ CONTENT: "#{BASE_CLASS}__content"
8
+ TOOLTIP: "#{BASE_CLASS}__tooltip"
9
+ PANE: "#{BASE_CLASS}__pane"
10
+
11
+ STATES =
12
+ BASE:
13
+ ACTIVE: "#{CLASSES.BASE}--is-active"
14
+ POSITIONED_BELOW: "#{CLASSES.BASE}--is-positioned-beneath"
15
+ POSITIONED_ABOVE: "#{CLASSES.BASE}--is-positioned-above"
16
+ CONTAINER:
17
+ ACTIVE: "#{CLASSES.CONTAINER}--contains-active-popover"
18
+ DEACTIVATING: "#{CLASSES.CONTAINER}--is-deactivating"
19
+
20
+ VARIANTS =
21
+ BASE:
22
+ ALIGN_TO_EDGE: "#{CLASSES.BASE}--align-to-edge"
23
+ FULL_WIDTH: "#{CLASSES.BASE}--full-width"
24
+
25
+ EVENTS =
26
+ ACTIVATED: "#{CLASSES.BASE}:activated"
27
+ DEACTIVATED: "#{CLASSES.BASE}:deactivated"
28
+
29
+ ATTRS =
30
+ PREFERRED_POSITION: "data-popover-preferred-position"
31
+ HORIZONTALLY_RELATIVE_TO: "data-popover-horizontally-relative-to-closest"
32
+ ACTIVATE_FROM: "data-popover-activate-from"
33
+ CSS_CACHE:
34
+ MAX_HEIGHT: "data-popover-css-max-height"
35
+ MAX_WIDTH: "data-popover-css-max-width"
36
+ VERTICAL_MARGIN: "data-popover-css-vertical-margin"
37
+ HORIZONTAL_MARGIN: "data-popover-css-horizontal-margin"
38
+
39
+ POSITIONS =
40
+ TOP: "top"
41
+ BOTTOM: "bottom"
42
+
43
+ TOOLTIP_SIZE = 5
44
+
45
+
46
+
47
+ # PUBLIC API AND HANDLERS
48
+
49
+ Popover = (node) ->
50
+ existingObject = Popover.for(node)
51
+ return existingObject if existingObject
52
+
53
+ activator = $(node).siblings(":not(#{CLASSES.BASE})")[0]
54
+ cachePopoverCSSProperties(node)
55
+ a11yPopovers(node, activator)
56
+
57
+ popoverManipulator =
58
+ activate: ->
59
+ activate(node)
60
+ return
61
+
62
+ deactivate: ->
63
+ deactivate(node)
64
+ return
65
+
66
+ toggle: ->
67
+ toggle(node)
68
+ return
69
+
70
+ reposition: ->
71
+ positionPopover()
72
+ return
73
+
74
+ $(node).data(CLASSES.BASE, popoverManipulator)
75
+ popoverManipulator
76
+
77
+ Popover.for = (node) ->
78
+ $(node).closest(".#{CLASSES.BASE}").data(CLASSES.BASE)
79
+
80
+ Popover.send = (method, args...) ->
81
+ if args.length
82
+ secrets[method]?.apply(null, args)
83
+ else
84
+ secrets[method]
85
+
86
+ Popover.CLASSES = CLASSES
87
+ Popover.EVENTS = EVENTS
88
+ Popover.STATES = STATES
89
+ Popover.VARIANTS = VARIANTS
90
+ Popover.ATTRS = ATTRS
91
+
92
+ window.Docks.Popover = Popover
93
+
94
+
95
+
96
+ # INITIALIZERS
97
+
98
+ popoverIndex = 1
99
+
100
+ joinToExistingIDs = (id, node) ->
101
+ currentID = node.id
102
+ node.id = "#{id}#{if currentID.length then " " else ""}#{currentID}"
103
+
104
+ a11yPopovers = (popover, activator) ->
105
+ # Define initial accessibility concerns
106
+ popoverID = "#{CLASSES.BASE}--#{popoverIndex++}"
107
+ activatorID = popoverID.replace(CLASSES.BASE, "#{CLASSES.BASE}-activator")
108
+
109
+ $(popover).attr
110
+ "id": joinToExistingIDs(popoverID, popover)
111
+ "aria-labelledby": activatorID
112
+ "aria-expanded": "false"
113
+
114
+ popover.style.display = "none"
115
+
116
+ $(activator).attr
117
+ "id": joinToExistingIDs(activatorID, activator)
118
+ "aria-expanded": "false"
119
+ "aria-haspopup": "true"
120
+ "aria-owns": popoverID
121
+ "aria-controls": popoverID
122
+
123
+ cachePopoverCSSProperties = (popover) ->
124
+ styles = window.getComputedStyle(popover)
125
+
126
+ popover.setAttribute(ATTRS.CSS_CACHE.VERTICAL_MARGIN, calculatePixelDimension(styles.marginTop, popover) || 0)
127
+ popover.setAttribute(ATTRS.CSS_CACHE.HORIZONTAL_MARGIN, calculatePixelDimension(styles.marginLeft, popover) || 0)
128
+
129
+ contentWrapper = $(popover).children(".#{CLASSES.CONTENT_WRAPPER}")[0]
130
+ contentWrapperStyles = window.getComputedStyle(contentWrapper)
131
+ popover.setAttribute(ATTRS.CSS_CACHE.MAX_HEIGHT, calculatePixelDimension(contentWrapperStyles.maxHeight, contentWrapper) || 10000)
132
+ popover.setAttribute(ATTRS.CSS_CACHE.MAX_WIDTH, calculatePixelDimension(contentWrapperStyles.maxWidth, contentWrapper) || 10000)
133
+
134
+ popover.style.maxWidth = "none" unless popover.classList.contains(VARIANTS.BASE.FULL_WIDTH)
135
+ popover.style.marginLeft = popover.style.marginRight = "0px"
136
+
137
+
138
+
139
+ # MEASUREMENT CONVERTERS
140
+
141
+ baseFontSize = do ->
142
+ fontSize = undefined
143
+
144
+ ->
145
+ return fontSize if fontSize?
146
+
147
+ $el = $("<div>M</div>").appendTo("body")
148
+ $el.css
149
+ display: "inline-block"
150
+ padding: "0"
151
+ lineHeight: "1"
152
+ position: "absolute"
153
+ visibility: "hidden"
154
+ fontSize: "1em"
155
+
156
+ size = $el.height()
157
+ $el.remove()
158
+ fontSize
159
+
160
+ calculatePixelDimension = (dim, node) ->
161
+ # No value set, make it non-restricting
162
+ return false if dim == "none"
163
+
164
+ float = parseFloat(dim)
165
+ return float * baseFontSize() if dim.indexOf("rem") >= 0
166
+ return float * parseFloat(window.getComputedStyle(node).fontSize) if dim.indexOf("em") >= 0
167
+ return float / 100 if dim.indexOf("%") >= 0
168
+
169
+ # Set in px
170
+ float
171
+
172
+
173
+
174
+ # CHANGING STATE
175
+
176
+ activeCache = {}
177
+
178
+ activate = (popover) ->
179
+ return if popover == activeCache.popover?.base
180
+ deactivate() if activeCache.popover
181
+
182
+ tooltip = popover.querySelector(".#{CLASSES.TOOLTIP}")
183
+ activator = popover.nextElementSibling || popover.previousElementSibling
184
+
185
+ relativeTo = popover.getAttribute(ATTRS.HORIZONTALLY_RELATIVE_TO)
186
+ activateFrom = popover.getAttribute(ATTRS.ACTIVATE_FROM)
187
+
188
+ activeCache =
189
+ container: popover.parentNode
190
+ activator: activator
191
+ source: if activateFrom then activator.querySelector(activateFrom) else activator
192
+ relativeTo: $(popover).closest(relativeTo)[0] if relativeTo
193
+ preferredPosition: popover.getAttribute(ATTRS.PREFERRED_POSITION) || POSITIONS.BOTTOM
194
+ horizontallyPosition: !popover.classList.contains(VARIANTS.BASE.FULL_WIDTH)
195
+ positionAgainstEdge: popover.classList.contains(VARIANTS.BASE.ALIGN_TO_EDGE)
196
+ popover:
197
+ base: popover
198
+ container: popover.parentNode
199
+ content: popover.querySelector(".#{CLASSES.CONTENT}")
200
+ contentWrapper: popover.querySelector(".#{CLASSES.CONTENT_WRAPPER}")
201
+ tooltip: tooltip
202
+ panes: Array::slice.call(popover.querySelectorAll(".#{CLASSES.PANE}"))
203
+ styles:
204
+ horizontalMargin: parseInt(popover.getAttribute(ATTRS.CSS_CACHE.HORIZONTAL_MARGIN))
205
+ verticalMargin: parseInt(popover.getAttribute(ATTRS.CSS_CACHE.VERTICAL_MARGIN))
206
+ maxHeight: parseInt(popover.getAttribute(ATTRS.CSS_CACHE.MAX_HEIGHT))
207
+ maxWidth: parseFloat(popover.getAttribute(ATTRS.CSS_CACHE.MAX_WIDTH))
208
+
209
+ ended = false
210
+ $(popover).one "transitionend webkitTransitionEnd", ->
211
+ return if ended
212
+ ended = true
213
+ $(popover).trigger(EVENTS.ACTIVATED)
214
+
215
+ attachActiveEventListeners(popover)
216
+ applyActivationMarkup()
217
+ positionPopover()
218
+
219
+ applyActivationMarkup = ->
220
+ popover = activeCache.popover.base
221
+ popover.style.backfaceVisibility = "hidden"
222
+ popover.style.display = ""
223
+ popover.setAttribute("aria-expanded", "true")
224
+ activeCache.activator.setAttribute("aria-expanded", "true")
225
+
226
+ popover.offsetHeight # force repaint
227
+ popover.classList.add(STATES.BASE.ACTIVE)
228
+ activeCache.popover.container.classList.add(STATES.CONTAINER.ACTIVE)
229
+ return
230
+
231
+ attachActiveEventListeners = (popover) ->
232
+ $(popover).on("wheel", ".#{CLASSES.PANE}", popoverPaneScroll)
233
+
234
+ toggle = (popover) ->
235
+ if activeCache.popover?.base != popover then activate(popover) else deactivate()
236
+
237
+ deactivate = (popover) ->
238
+ return unless activeCache.popover
239
+ return if popover && popover != activeCache.popover.base
240
+
241
+ oldPopover = activeCache.popover.base
242
+ oldContent = activeCache.popover.content
243
+ oldContainer = activeCache.popover.container
244
+
245
+ $(oldPopover).one "transitionend webkitTransitionEnd", do ->
246
+ # Fixes a Chrome bug where transitionend and webkitTransitionEnd
247
+ # events both fired
248
+ ended = false
249
+
250
+ ->
251
+ return if ended
252
+ ended = true
253
+ oldContainer.classList.remove(STATES.CONTAINER.DEACTIVATING)
254
+ oldPopover.style.display = "none"
255
+ oldPopover.style.backfaceVisibility = ""
256
+ oldContent.style.width = ""
257
+ $(oldPopover).trigger(EVENTS.DEACTIVATED)
258
+
259
+ applyDeactivationMarkup()
260
+ detachActiveEventListeners(oldPopover)
261
+
262
+ # delete so we keep the reference to activeCache in secrets
263
+ delete activeCache[key] for key of activeCache
264
+
265
+ applyDeactivationMarkup = ->
266
+ popover = activeCache.popover
267
+ popover.container.classList.add(STATES.CONTAINER.DEACTIVATING)
268
+ popover.container.classList.remove(STATES.CONTAINER.ACTIVE)
269
+ popover.base.classList.remove(STATES.BASE.ACTIVE)
270
+ popover.base.setAttribute("aria-expanded", "false")
271
+ activeCache.activator.setAttribute("aria-expanded", "false")
272
+
273
+ detachActiveEventListeners = (popover) ->
274
+ $(popover).off("wheel", ".#{CLASSES.PANE}", popoverPaneScroll)
275
+
276
+
277
+
278
+ # SIZING AND POSITIONING
279
+
280
+ positionPopover = (event) ->
281
+ return unless activeCache.popover
282
+
283
+ resize = !event?.type || event.type == "resize"
284
+ newStyles =
285
+ base: {}
286
+ wrapper: {}
287
+ content: {}
288
+ tooltip: {}
289
+
290
+ rect = spaceDetailsForActivePopover()
291
+ determineVerticalPositioning({ rect: rect }, newStyles)
292
+
293
+ # Horizontal repositioning only needs to happen on resize
294
+ if resize && activeCache.horizontallyPosition
295
+ offsets = calculateHorizontalOffsets()
296
+ left = rect.leftRelative <= 0.5
297
+ width = calculateMaxWidth(rect.relativeToWidth)
298
+ newStyles.content.width = width
299
+
300
+ context =
301
+ offsets: offsets
302
+ width: width
303
+ left: left
304
+ rect: rect
305
+
306
+ if activeCache.positionAgainstEdge
307
+ horizontallyPositionWithEdgeAlignment(context, newStyles)
308
+ else
309
+ horizontallyPositionWithCenterAlignment(context, newStyles)
310
+
311
+ tooltipPosition = (rect.width / 2) + offsets.leftFromContainerToActivator + offsets.leftFromActivatorToSource - newStyles.base.left
312
+ newStyles.tooltip.left = tooltipPosition
313
+
314
+ popoverStyles = activeCache.popover.base.style
315
+ transformOriginY = newStyles.base.transformOrigin.split(" ")[1..-1].join(" ")
316
+ activeCache.styles.transformOriginX = "#{Math.round(tooltipPosition)}px"
317
+ newStyles.base.transformOrigin = "#{activeCache.styles.transformOriginX} #{transformOriginY}"
318
+
319
+ requestAnimationFrame ->
320
+ popover = activeCache.popover
321
+ $(popover.base).css(newStyles.base)
322
+ $(popover.content).css(newStyles.content)
323
+ $(popover.contentWrapper).css(newStyles.wrapper)
324
+ $(popover.tooltip).css(newStyles.tooltip)
325
+
326
+ if resize
327
+ # Safari and IE need an explicit height for the content, otherwise the flexbox
328
+ # will set non-fixed panes to be a height of 0. This **must** be done after
329
+ # the content's width is set since width dictates the height.
330
+ popover.content.style.height = calculateTotalPaneSize() + 2
331
+
332
+ # $.css doesn't apply the transformOrigin in IE for some reason :/
333
+ popover.base.style.transformOrigin = newStyles.base.transformOrigin
334
+
335
+ horizontallyPositionWithEdgeAlignment = (context, styles) ->
336
+ {offsets, width, rect, left} = context
337
+
338
+ oppositeSideSpace = rect[if left then "right" else "left"] + (rect.width / 2) - activeCache.styles.horizontalMargin
339
+
340
+ popoverPosition = if left then 0 else rect.width - width
341
+ popoverPosition += offsets.leftFromContainerToActivator
342
+
343
+ styles.base.left = if width > oppositeSideSpace
344
+ if left
345
+ popoverPosition - (width - oppositeSideSpace) - offsets.leftFromActivatorToSource
346
+ else
347
+ popoverPosition + (width - oppositeSideSpace)
348
+ else
349
+ if left
350
+ popoverPosition - offsets.leftFromActivatorToSource
351
+ else
352
+ popoverPosition - offsets.rightFromActivatorToSource
353
+
354
+ styles.base.left += offsets.leftFromActivatorToSource
355
+
356
+ horizontallyPositionWithCenterAlignment = (context, styles) ->
357
+ {offsets, width, rect, left} = context
358
+
359
+ spaceNeededPerSide = (width * 0.5) + activeCache.styles.horizontalMargin
360
+
361
+ styles.base.left = if left && rect.left < spaceNeededPerSide
362
+ (rect.width / 2) + activeCache.styles.horizontalMargin - rect.left
363
+ else if !left && rect.right < spaceNeededPerSide
364
+ (rect.width / 2) - width + rect.right - activeCache.styles.horizontalMargin
365
+ else
366
+ (rect.width / 2) - (width / 2)
367
+
368
+ styles.base.left = styles.base.left + offsets.leftFromContainerToActivator + offsets.leftFromActivatorToSource
369
+
370
+ calculateHorizontalOffsets = ->
371
+ activatorRect = activeCache.activator.getBoundingClientRect()
372
+ sourceIsActivator = activeCache.source == activeCache.activator
373
+ sourceRect = if sourceIsActivator then activatorRect else activeCache.source.getBoundingClientRect()
374
+
375
+ leftFromContainerToActivator: activatorRect.left - activeCache.container.getBoundingClientRect().left
376
+ leftFromActivatorToSource: sourceRect.left - activatorRect.left
377
+ rightFromActivatorToSource: sourceRect.right - activatorRect.right
378
+
379
+ spaceDetailsForActivePopover = ->
380
+ rect = activeCache.source.getBoundingClientRect()
381
+ topSpace = rect.top + (0.5 * rect.height)
382
+ leftSpace = rect.left + (0.5 * rect.width)
383
+ relativeToWidth = window.innerWidth
384
+
385
+ if activeCache.relativeTo
386
+ relativeTo = activeCache.relativeTo.getBoundingClientRect()
387
+ relativeToWidth = relativeTo.width
388
+ leftSpace -= relativeTo.left
389
+
390
+ height: rect.height
391
+ width: rect.width
392
+ top: topSpace
393
+ bottom: window.innerHeight - topSpace
394
+ left: leftSpace
395
+ leftRelative: leftSpace / relativeToWidth
396
+ right: relativeToWidth - leftSpace
397
+ relativeToWidth: relativeToWidth
398
+
399
+ calculateTotalPaneSize = do ->
400
+ reduction = (totalHeight, pane) -> totalHeight + pane.scrollHeight
401
+
402
+ -> activeCache.popover.panes.reduce(reduction, 0)
403
+
404
+ calculateMaxWidth = (relativeToWidth) ->
405
+ unless activeCache.styles.contentWidth
406
+ content = activeCache.popover.content
407
+ content.style.whiteSpace = "nowrap"
408
+ activeCache.styles.contentWidth = content.offsetWidth + 2
409
+ content.style.whiteSpace = ""
410
+
411
+ # Adjust for percentage-based max width
412
+ maxRelativeWidth = relativeToWidth - (2 * activeCache.styles.horizontalMargin)
413
+ Math.min(maxRelativeWidth, activeCache.styles.maxWidth, activeCache.styles.contentWidth)
414
+
415
+ determineVerticalPositioning = (context, styles) ->
416
+ actualHeight = activeCache.popover.base.offsetHeight + 2 * activeCache.styles.verticalMargin
417
+ spaceAvailable = context.rect
418
+
419
+ position = if activeCache.preferredPosition == POSITIONS.BOTTOM
420
+ if spaceAvailable.bottom > spaceAvailable.top ||
421
+ (spaceAvailable.bottom - spaceAvailable.height / 2) > actualHeight
422
+ POSITIONS.BOTTOM
423
+ else
424
+ POSITIONS.TOP
425
+ else
426
+ if spaceAvailable.top > spaceAvailable.bottom ||
427
+ (spaceAvailable.top - spaceAvailable.height / 2) > actualHeight
428
+ POSITIONS.TOP
429
+ else
430
+ POSITIONS.BOTTOM
431
+
432
+ positionedAbove = position == POSITIONS.TOP
433
+ defaultHorizontalTranslation = if activeCache.horizontallyPosition then 0 else "50%"
434
+ styles.base.transformOrigin = if positionedAbove
435
+ "#{activeCache.styles.transformOriginX || defaultHorizontalTranslation} calc(100% + #{TOOLTIP_SIZE}px)"
436
+ else
437
+ "#{activeCache.styles.transformOriginX || defaultHorizontalTranslation} -#{TOOLTIP_SIZE}px"
438
+
439
+ if position != activeCache.position
440
+ activeCache.position = position
441
+ activeCache.popover.base.classList[if positionedAbove then "remove" else "add"](STATES.BASE.POSITIONED_BELOW)
442
+ activeCache.popover.base.classList[if positionedAbove then "add" else "remove"](STATES.BASE.POSITIONED_ABOVE)
443
+
444
+ maxHeightOnScreen = spaceAvailable[position] - (spaceAvailable.height / 2) - (2 * activeCache.styles.verticalMargin)
445
+ styles.content.maxHeight = Math.min(maxHeightOnScreen, activeCache.styles.maxHeight)
446
+
447
+
448
+
449
+ # EVENT HANDLERS
450
+
451
+ popoverFocus = do ->
452
+ lastCallAt = 0
453
+ lastPopoverContainer = null
454
+
455
+ (event) ->
456
+ $target = $(event.target)
457
+ return if $target.closest(".#{CLASSES.BASE}").length
458
+
459
+ $popoverContainer = $target.closest(".#{CLASSES.CONTAINER}")
460
+
461
+ if $popoverContainer.length
462
+
463
+ # manual throttling only if the same popover is triggered multiple times in a row
464
+ currentPopoverContainer = $popoverContainer[0]
465
+ now = Date.now()
466
+ if lastPopoverContainer == currentPopoverContainer && (now - lastCallAt) < 300
467
+ return
468
+ lastCallAt = now
469
+ lastPopoverContainer = currentPopoverContainer
470
+
471
+ event.preventDefault()
472
+ node = $popoverContainer.children(".#{CLASSES.BASE}")[0]
473
+ if event.type == 'focusin'
474
+ activate(node)
475
+ else
476
+ toggle(node)
477
+
478
+ else
479
+ deactivate()
480
+
481
+ popoverKeydown = (event) ->
482
+ return if $(event.target).closest(".#{CLASSES.BASE}").length
483
+ popover = $(event.currentTarget).children(".#{CLASSES.BASE}")[0]
484
+
485
+ if event.which in [Shopify.Keycodes.ENTER, Shopify.Keycodes.SPACE]
486
+ toggle(popover)
487
+ event.preventDefault()
488
+
489
+ else if event.which == Shopify.Keycodes.ESCAPE
490
+ deactivate()
491
+ event.preventDefault()
492
+
493
+ return
494
+
495
+ popoverPaneScroll = (event) ->
496
+ pane = event.currentTarget
497
+ delta = event.originalEvent.deltaY
498
+ up = delta < 0
499
+
500
+ [height, scrollHeight, scrollTop] = [
501
+ pane.offsetHeight
502
+ pane.scrollHeight
503
+ pane.scrollTop
504
+ ]
505
+
506
+ prevent = ->
507
+ event.stopPropagation()
508
+ event.preventDefault()
509
+
510
+ scrollingDownPastBottom = !up && delta > scrollHeight - height - scrollTop
511
+ scrollingUpPastTop = up && -delta > scrollTop
512
+
513
+ if scrollingDownPastBottom
514
+ pane.scrollTop = scrollHeight
515
+ prevent()
516
+
517
+ if scrollingUpPastTop
518
+ pane.scrollTop = 0
519
+ prevent()
520
+
521
+ return
522
+
523
+
524
+
525
+ # Store app private methods in a secret object so we can access them
526
+ # on Popover.send(method)
527
+
528
+ secrets =
529
+ activeCache: activeCache
530
+
531
+ joinToExistingIDs: joinToExistingIDs
532
+ a11yPopovers: a11yPopovers
533
+ cachePopoverCSSProperties: cachePopoverCSSProperties
534
+
535
+ baseFontSize: baseFontSize
536
+ calculatePixelDimension: calculatePixelDimension
537
+
538
+ activate: activate
539
+ applyActivationMarkup: applyActivationMarkup
540
+ attachActiveEventListeners: attachActiveEventListeners
541
+ toggle: toggle
542
+ deactivate: deactivate
543
+ applyDeactivationMarkup: applyDeactivationMarkup
544
+ detachActiveEventListeners: detachActiveEventListeners
545
+
546
+ positionPopover: positionPopover
547
+ horizontallyPositionWithCenterAlignment: horizontallyPositionWithCenterAlignment
548
+ horizontallyPositionWithEdgeAlignment: horizontallyPositionWithEdgeAlignment
549
+ calculateHorizontalOffsets: calculateHorizontalOffsets
550
+ spaceDetailsForActivePopover: spaceDetailsForActivePopover
551
+ calculateMaxWidth: calculateMaxWidth
552
+ determineVerticalPositioning: determineVerticalPositioning
553
+
554
+ popoverFocus: popoverFocus
555
+ popoverKeydown: popoverKeydown
556
+ popoverPaneScroll: popoverPaneScroll
557
+
558
+ Lemon.make(Popover)
559
+
560
+ $(document).on("click focusin", popoverFocus)
561
+ $(document).on("keydown", ".#{CLASSES.CONTAINER}", popoverKeydown)
562
+ $(window).on("resize scroll", positionPopover)
@@ -0,0 +1,21 @@
1
+ <%
2
+ popover.configure do |config|
3
+ config.defaults(align: :center, relative_to: nil)
4
+ config.classes(base: "popover")
5
+
6
+ config.conditional_classes with: :align do |alignment|
7
+ { base: "popover--align-to-#{alignment}" }
8
+ end
9
+ end
10
+ %>
11
+
12
+ <div class="<%= popover.classes_for(:base) %>"<% unless popover.relative_to.nil? %> data-popover-horizontally-relative-to-closest="<%= popover.relative_to %>"<% end %>>
13
+ <div class="popover__tooltip"></div>
14
+ <div class="popover__content-wrapper">
15
+ <div class="popover__content">
16
+ <% if popover.block %>
17
+ <%= capture(popover, &popover.block) %>
18
+ <% end %>
19
+ </div>
20
+ </div>
21
+ </div>
File without changes