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.
- checksums.yaml +15 -0
- data/.babelrc +4 -0
- data/.editorconfig +8 -0
- data/.eslintrc +115 -0
- data/.gitignore +24 -0
- data/.rubocop.yml +20 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/README.md +5 -0
- data/Rakefile +3 -0
- data/assets/images/icons.svg +63 -0
- data/assets/scripts/coffeescript/pattern_library_helpers.coffee +8 -0
- data/assets/scripts/javascript/pattern_library_helpers.js +11 -0
- data/assets/scripts/pattern_library.js +10380 -0
- data/assets/scripts/pattern_library_demo.js +0 -0
- data/assets/styles/less/pattern-library-helpers.less +103 -0
- data/assets/styles/pattern-library-demo.css +1882 -0
- data/assets/styles/pattern-library.css +1882 -0
- data/assets/styles/sass/pattern-library-helpers.sass +90 -0
- data/assets/styles/scss/pattern-library-helpers.scss +99 -0
- data/assets/styles/stylus/pattern-library-helpers.styl +90 -0
- data/assets/templates/erb/demo.erb +26 -0
- data/assets/templates/erb/layouts/demo.erb +17 -0
- data/assets/templates/erb/layouts/pattern.erb +76 -0
- data/assets/templates/erb/partials/sidebar.erb +124 -0
- data/assets/templates/erb/partials/symbols/class.erb +1 -0
- data/assets/templates/erb/partials/symbols/demo.erb +40 -0
- data/assets/templates/erb/partials/symbols/factory.erb +70 -0
- data/assets/templates/erb/partials/symbols/function.erb +103 -0
- data/assets/templates/erb/partials/symbols/mixin.erb +62 -0
- data/assets/templates/erb/partials/symbols/variable.erb +59 -0
- data/assets/templates/erb/pattern.erb +102 -0
- data/assets/templates/haml/demo.haml +14 -0
- data/assets/templates/haml/layouts/demo.haml +6 -0
- data/assets/templates/haml/layouts/pattern.haml +38 -0
- data/assets/templates/haml/partials/sidebar.haml +68 -0
- data/assets/templates/haml/partials/symbols/class.haml +1 -0
- data/assets/templates/haml/partials/symbols/demo.haml +23 -0
- data/assets/templates/haml/partials/symbols/factory.haml +38 -0
- data/assets/templates/haml/partials/symbols/function.haml +54 -0
- data/assets/templates/haml/partials/symbols/mixin.haml +31 -0
- data/assets/templates/haml/partials/symbols/variable.haml +22 -0
- data/assets/templates/haml/pattern.haml +54 -0
- data/assets/templates/slim/demo.slim +24 -0
- data/assets/templates/slim/layouts/demo.slim +5 -0
- data/assets/templates/slim/layouts/pattern.slim +48 -0
- data/assets/templates/slim/partials/sidebar.slim +112 -0
- data/assets/templates/slim/partials/symbols/class.slim +1 -0
- data/assets/templates/slim/partials/symbols/demo.slim +30 -0
- data/assets/templates/slim/partials/symbols/factory.slim +57 -0
- data/assets/templates/slim/partials/symbols/function.slim +81 -0
- data/assets/templates/slim/partials/symbols/mixin.slim +45 -0
- data/assets/templates/slim/partials/symbols/variable.slim +35 -0
- data/assets/templates/slim/pattern.slim +63 -0
- data/docks_config.rb +32 -0
- data/docks_theme_api.gemspec +37 -0
- data/gulpfile.js +88 -0
- data/karma.conf.js +6 -0
- data/lib/docks_theme_api/components/base_component.rb +99 -0
- data/lib/docks_theme_api/components/code_block_component.rb +10 -0
- data/lib/docks_theme_api/components/popover_component.rb +15 -0
- data/lib/docks_theme_api/components/table_component.rb +34 -0
- data/lib/docks_theme_api/components/tablist_component.rb +11 -0
- data/lib/docks_theme_api/components.rb +21 -0
- data/lib/docks_theme_api/helpers/ui_helper.rb +69 -0
- data/lib/docks_theme_api/theme.rb +21 -0
- data/lib/docks_theme_api.rb +1 -0
- data/package.json +60 -0
- data/source/behaviors/filterable/filterable.coffee +353 -0
- data/source/behaviors/filterable/filterable.js +0 -0
- data/source/behaviors/filterable/filterable.scss +34 -0
- data/source/behaviors/filterable/package.json +3 -0
- data/source/behaviors/index.js +0 -0
- data/source/components/avatar/avatar.erb +20 -0
- data/source/components/avatar/avatar.js +142 -0
- data/source/components/avatar/avatar.scss +200 -0
- data/source/components/avatar/avatar_container.erb +13 -0
- data/source/components/avatar/package.json +3 -0
- data/source/components/avatar/spec/avatar_spec.js +81 -0
- data/source/components/badge/badge.scss +158 -0
- data/source/components/button/button.scss +213 -0
- data/source/components/card/card.scss +32 -0
- data/source/components/code_block/code-block.scss +353 -0
- data/source/components/code_block/code_block.erb +95 -0
- data/source/components/code_block/code_block.js +444 -0
- data/source/components/code_block/package.json +3 -0
- data/source/components/code_block/spec/code_block_spec.js +10 -0
- data/source/components/demo/demo.js +244 -0
- data/source/components/demo/demo.scss +90 -0
- data/source/components/demo/package.json +3 -0
- data/source/components/exploded/exploded.erb +25 -0
- data/source/components/exploded/exploded.js +694 -0
- data/source/components/exploded/exploded.scss +166 -0
- data/source/components/exploded/package.json +3 -0
- data/source/components/field/field.js +24 -0
- data/source/components/field/field.scss +101 -0
- data/source/components/field/package.json +3 -0
- data/source/components/header/header.scss +33 -0
- data/source/components/iframe/iframe.erb +12 -0
- data/source/components/iframe/iframe.js +381 -0
- data/source/components/iframe/package.json +3 -0
- data/source/components/index.js +37 -0
- data/source/components/inline_group/inline-group.scss +14 -0
- data/source/components/internal_link/internal_link.js +49 -0
- data/source/components/internal_link/package.json +3 -0
- data/source/components/list/list.scss +230 -0
- data/source/components/modal/modal.coffee +84 -0
- data/source/components/modal/modal.erb +19 -0
- data/source/components/modal/modal.js +0 -0
- data/source/components/modal/modal.scss +57 -0
- data/source/components/modal/package.json +3 -0
- data/source/components/notice/notice.scss +48 -0
- data/source/components/popover/package.json +3 -0
- data/source/components/popover/popover.coffee +562 -0
- data/source/components/popover/popover.erb +21 -0
- data/source/components/popover/popover.js +0 -0
- data/source/components/popover/popover.scss +139 -0
- data/source/components/range/range.scss +78 -0
- data/source/components/resizable/package.json +3 -0
- data/source/components/resizable/resizable.erb +30 -0
- data/source/components/resizable/resizable.js +250 -0
- data/source/components/resizable/resizable.scss +245 -0
- data/source/components/resizable/size_buttons.js +249 -0
- data/source/components/scroll_container/package.json +3 -0
- data/source/components/scroll_container/scroll-container.scss +4 -0
- data/source/components/scroll_container/scroll_container.js +24 -0
- data/source/components/section/section.scss +99 -0
- data/source/components/select/package.json +3 -0
- data/source/components/select/select.erb +21 -0
- data/source/components/select/select.js +35 -0
- data/source/components/select/select.scss +163 -0
- data/source/components/table/package.json +3 -0
- data/source/components/table/table.erb +16 -0
- data/source/components/table/table.js +351 -0
- data/source/components/table/table.scss +236 -0
- data/source/components/tablist/package.json +3 -0
- data/source/components/tablist/tablist.erb +13 -0
- data/source/components/tablist/tablist.js +246 -0
- data/source/components/tablist/tablist.scss +191 -0
- data/source/components/tablist/tablist_panel.erb +14 -0
- data/source/components/tablist/tablist_tab.erb +20 -0
- data/source/components/toggle/package.json +3 -0
- data/source/components/toggle/toggle.erb +11 -0
- data/source/components/toggle/toggle.js +211 -0
- data/source/components/toggle/toggle_container.erb +30 -0
- data/source/components/vertical_spacer/vertical-spacer.scss +3 -0
- data/source/components/vertical_stack/vertical-stack.scss +19 -0
- data/source/components/xray/package.json +3 -0
- data/source/components/xray/xray.erb +50 -0
- data/source/components/xray/xray.js +123 -0
- data/source/components/xray/xray.scss +79 -0
- data/source/foundation/app/app.js +15 -0
- data/source/foundation/app/package.json +3 -0
- data/source/pattern-library-demo.scss +13 -0
- data/source/pattern-library.scss +13 -0
- data/source/pattern_library.js +8 -0
- data/source/pattern_library_demo.js +8 -0
- data/source/structures/index.js +11 -0
- data/source/structures/sidebar/package.json +3 -0
- data/source/structures/sidebar/sidebar.js +69 -0
- data/source/structures/sidebar/sidebar.scss +79 -0
- data/source/utilities/builder/builder.js +138 -0
- data/source/utilities/builder/package.json +3 -0
- data/source/utilities/client/client.js +7 -0
- data/source/utilities/client/package.json +3 -0
- data/source/utilities/colors/colors.scss +112 -0
- data/source/utilities/defaults/defaults.scss +38 -0
- data/source/utilities/dom_cache/dom_cache.js +24 -0
- data/source/utilities/dom_cache/package.json +3 -0
- data/source/utilities/events/events.js +25 -0
- data/source/utilities/events/package.json +3 -0
- data/source/utilities/font_sizes/font-sizes.scss +85 -0
- data/source/utilities/foundation/a11y.scss +10 -0
- data/source/utilities/foundation/base.scss +29 -0
- data/source/utilities/foundation/icon.scss +114 -0
- data/source/utilities/foundation/layout.scss +67 -0
- data/source/utilities/foundation/page.scss +39 -0
- data/source/utilities/foundation/type.scss +208 -0
- data/source/utilities/functions/functions.scss +127 -0
- data/source/utilities/keycodes/keycodes.js +23 -0
- data/source/utilities/keycodes/package.json +3 -0
- data/source/utilities/markup/markup.js +90 -0
- data/source/utilities/markup/package.json +3 -0
- data/source/utilities/media/media.scss +172 -0
- data/source/utilities/mixins/mixins.scss +89 -0
- data/source/utilities/naming_convention/naming_convention.js +3 -0
- data/source/utilities/naming_convention/package.json +3 -0
- data/source/utilities/numbers/numbers.js +14 -0
- data/source/utilities/numbers/package.json +3 -0
- data/source/utilities/painting/package.json +3 -0
- data/source/utilities/painting/painting.js +7 -0
- data/source/utilities/pattern/package.json +3 -0
- data/source/utilities/pattern/pattern.js +50 -0
- data/source/utilities/query_string/package.json +3 -0
- data/source/utilities/query_string/query_string.js +24 -0
- data/source/utilities/template/package.json +3 -0
- data/source/utilities/template/template.js +10 -0
- data/source/utilities/text_range/package.json +3 -0
- data/source/utilities/text_range/text_range.js +30 -0
- data/source/utilities/ui_events/package.json +3 -0
- data/source/utilities/ui_events/ui_events.js +85 -0
- data/source/utilities/variables/variables.scss +18 -0
- data/source/utilities/z_indexes/z-indexes.scss +88 -0
- data/source/vendor/array_includes.js +28 -0
- data/source/vendor/highlight.js +1142 -0
- data/source/vendor/index.js +1 -0
- data/source/vendor/matrix.js +399 -0
- data/source/vendor/query_string.js +66 -0
- data/spec/assets/.eslintrc +9 -0
- data/spec/assets/spec_fixture.js +33 -0
- data/spec/assets/spec_helper.js +19 -0
- data/spec/lib/components/base_component_spec.rb +156 -0
- data/spec/lib/components_spec.rb +30 -0
- data/spec/lib/helpers/ui_helper_spec.rb +62 -0
- data/spec/lib/theme_spec.rb +25 -0
- data/spec/spec_helper.rb +15 -0
- data/tasks/gulp/.eslintrc +6 -0
- data/tasks/gulp/browser_sync.js +8 -0
- data/tasks/gulp/code_quality/scripts.js +10 -0
- data/tasks/gulp/config/index.js +116 -0
- data/tasks/gulp/minify/scripts.js +13 -0
- data/tasks/gulp/minify/styles.js +13 -0
- data/tasks/gulp/pattern_library/index.js +5 -0
- data/tasks/gulp/pattern_library/scripts.js +10 -0
- data/tasks/gulp/pattern_library/styles.js +10 -0
- data/tasks/gulp/scripts.js +8 -0
- data/tasks/gulp/spec/scripts.js +11 -0
- data/tasks/gulp/styles.js +17 -0
- data/tasks/gulp/utilities/babel/relative_require.js +22 -0
- data/tasks/gulp/utilities/babel/spec_helper.js +20 -0
- data/tasks/gulp/utilities/browserify_bundler.js +22 -0
- data/tasks/gulp/utilities/handle_errors.js +13 -0
- data/tasks/gulp/watch.js +9 -0
- data/tasks/rake/rspec.rake +7 -0
- data/tasks/rake/rubocop.rake +8 -0
- data/tasks/rake/templates.rake +50 -0
- metadata +470 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// ___ ___
|
|
2
|
+
// ___ / /\ _____ / /\
|
|
3
|
+
// / /\ / /::\ / /::\ / /:/_
|
|
4
|
+
// / /:/ / /:/\:\ / /:/\:\ ___ ___ / /:/ /\
|
|
5
|
+
// / /:/ / /:/~/::\ / /:/~/::\/__/\ / /\/ /:/ /:/_
|
|
6
|
+
// / /::\/__/:/ /:/\:\/__/:/ /:/\:\ \:\ / /:/__/:/ /:/ /\
|
|
7
|
+
// /__/:/\:\ \:\/:/__\/\ \:\/:/~/:/\ \:\ /:/\ \:\/:/ /:/
|
|
8
|
+
// \__\/ \:\ \::/ \ \::/ /:/ \ \:\/:/ \ \::/ /:/
|
|
9
|
+
// \ \:\ \:\ \ \:\/:/ \ \::/ \ \:\/:/
|
|
10
|
+
// \__\/\ \:\ \ \::/ \__\/ \ \::/
|
|
11
|
+
// \__\/ \__\/ \__\/
|
|
12
|
+
|
|
13
|
+
//*
|
|
14
|
+
// @pattern Table
|
|
15
|
+
//
|
|
16
|
+
// Tables are used to present tabular data only — never for layout! These tables
|
|
17
|
+
// are smarter than the average table, however. They will determine their
|
|
18
|
+
// intrinsic size (up to a stylesheet-specified maximum) and, when the space
|
|
19
|
+
// available to them is less than that size, they will begin to scroll.
|
|
20
|
+
//
|
|
21
|
+
// As you scroll, the first column will stay fixed, so you always have context,
|
|
22
|
+
// and the any given column will always be small enough to be fully visible. Not
|
|
23
|
+
// only that, but the table provides both keyboard input and interface elements
|
|
24
|
+
// that allow you to quickly shift to overscrolled columns.
|
|
25
|
+
//
|
|
26
|
+
// @since 1.0.0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
$table--border: 1px solid color(gray-light);
|
|
31
|
+
$table--border-radius: double(default(border-radius));
|
|
32
|
+
$table--box-shadow-size: 3px 0 4px -1px;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
//*
|
|
37
|
+
// A smarter `table` element. The `min-width` placed here will not actually
|
|
38
|
+
// be the minimum width of the rendered table; the provided minimum width will
|
|
39
|
+
// instead be used as the maximum width allowed in determining the preferred/
|
|
40
|
+
// intrinsic size of the table cells. That is, a table whose natural size is
|
|
41
|
+
// less than this amount will not overflow until the space it has is less than
|
|
42
|
+
// its intrinsic size, where a table with large cells will overflow at the
|
|
43
|
+
// provided `min-width` breakpoint.
|
|
44
|
+
//
|
|
45
|
+
// Visually, all tables will be 100% width. As noted above, tables will overflow
|
|
46
|
+
// once the lesser of the `min-width` below or the intrisic size of the table
|
|
47
|
+
// is reached. This overflowing is managed by the JavaScript component.
|
|
48
|
+
//
|
|
49
|
+
// @helper docks_table
|
|
50
|
+
|
|
51
|
+
.table {
|
|
52
|
+
width: 100%;
|
|
53
|
+
min-width: rem(500);
|
|
54
|
+
|
|
55
|
+
border-collapse: separate;
|
|
56
|
+
border-spacing: 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
//*
|
|
62
|
+
// The outermost wrapper around a table. This wrapper is used to signal to the
|
|
63
|
+
// entire component when the table is in overflow (via the
|
|
64
|
+
// `table__container--is-overflowing` state). Doing so on the outmost container
|
|
65
|
+
// allows adjustments to both the table itself and the `table__actions`.
|
|
66
|
+
//
|
|
67
|
+
// In addition, `table__containers` will automatically create the required
|
|
68
|
+
// space between themselves and other content.
|
|
69
|
+
|
|
70
|
+
.table__container {
|
|
71
|
+
margin: default(spacing) auto;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//*
|
|
75
|
+
// Signals to the `table` that it should force the first cell in each row
|
|
76
|
+
// to float about the rest of the rows (the required left padding on the
|
|
77
|
+
// second cell in each row to account for the absolutely-positioned first cell
|
|
78
|
+
// is done automatically by the JavaScript side of things, as is the
|
|
79
|
+
// equalization of all of the first cells' widths). Additionally, this
|
|
80
|
+
// state causes the `table__actions` to be made visible.
|
|
81
|
+
//
|
|
82
|
+
// @set_by Table#check_for_overflow
|
|
83
|
+
// @demo_type none
|
|
84
|
+
|
|
85
|
+
.table__container--is-overflowing {
|
|
86
|
+
.table__cell:first-child {
|
|
87
|
+
position: absolute;
|
|
88
|
+
@include z-index(cell-persistant, table);
|
|
89
|
+
left: 0;
|
|
90
|
+
|
|
91
|
+
height: 100%;
|
|
92
|
+
|
|
93
|
+
// Start box shadow as transparent so it can be animated into view when
|
|
94
|
+
// the table is actually being scrolled.
|
|
95
|
+
box-shadow: $table--box-shadow-size rgba(color(black), 0);
|
|
96
|
+
transition: box-shadow 0.2s ease;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.table__actions {
|
|
100
|
+
transform: translateY(0);
|
|
101
|
+
max-height: 3rem;
|
|
102
|
+
padding-bottom: half(default(spacing));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
//*
|
|
109
|
+
// A wrapper around the `table` that allows it to scroll when the minimum
|
|
110
|
+
// width of its columns (their intrinsic width or their width when the table
|
|
111
|
+
// is larger than the `min-width` set on `table`) is larger than the space
|
|
112
|
+
// available to this container.
|
|
113
|
+
|
|
114
|
+
.table__scroller {
|
|
115
|
+
max-width: 100%;
|
|
116
|
+
overflow-x: auto;
|
|
117
|
+
overflow-y: hidden;
|
|
118
|
+
-webkit-overflow-scrolling: touch;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//*
|
|
122
|
+
// The state that is added by the JavaScript component when the table is
|
|
123
|
+
// overflowed **and** the scroll position of this subcomponent is not fully
|
|
124
|
+
// pinned to the left.
|
|
125
|
+
//
|
|
126
|
+
// @set_by Table#handle_scroll, Table#shift_table
|
|
127
|
+
|
|
128
|
+
.table__scroller--is-scrolled {
|
|
129
|
+
.table__cell:first-child {
|
|
130
|
+
box-shadow: $table--box-shadow-size rgba(color(black), 0.1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
//*
|
|
137
|
+
// The wrapper around a `table` that provides a few visual pieces. Most
|
|
138
|
+
// noticeably, this adds the border and border radius on the outside of the
|
|
139
|
+
// table. These pieces must be on this container rather than the
|
|
140
|
+
// `table__container` subcomponent because it should only wrap around the
|
|
141
|
+
// `table`, and not the `table__actions`. These rules can't be on the
|
|
142
|
+
// `table__scroller` subcomponent, either, because it must be `overflow: hidden`
|
|
143
|
+
// (to hide the parts outside the rounded corners), where the scroller must
|
|
144
|
+
// be allowed to scroll.
|
|
145
|
+
//
|
|
146
|
+
// More importantly, however, this container is `position: relative` and, as
|
|
147
|
+
// such, acts as the element against which the persistant cells are
|
|
148
|
+
// positioned. These rules can't be on the `table__scroller` because it scrolls,
|
|
149
|
+
// where the persistant cells should be fixed even as the rest of the table
|
|
150
|
+
// scrolls.
|
|
151
|
+
|
|
152
|
+
.table__backdrop {
|
|
153
|
+
// position
|
|
154
|
+
position: relative;
|
|
155
|
+
@include z-index(backdrop, table);
|
|
156
|
+
|
|
157
|
+
// box model
|
|
158
|
+
max-width: 100%;
|
|
159
|
+
clear: both;
|
|
160
|
+
|
|
161
|
+
// backdrop
|
|
162
|
+
overflow: hidden;
|
|
163
|
+
border: $table--border;
|
|
164
|
+
border-radius: $table--border-radius;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
//*
|
|
170
|
+
// A container around the actions that can be performed on the `table`. For now,
|
|
171
|
+
// this includes only the segmented button to shift the table right/ left by
|
|
172
|
+
// one column.
|
|
173
|
+
|
|
174
|
+
.table__actions {
|
|
175
|
+
transform: translateY(140%);
|
|
176
|
+
max-height: 0;
|
|
177
|
+
float: right;
|
|
178
|
+
|
|
179
|
+
transition: transform 0.3s $bouncy-transition,
|
|
180
|
+
max-height 0.3s ease,
|
|
181
|
+
padding-bottom 0.3s ease;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
//*
|
|
187
|
+
// The header row of the table.
|
|
188
|
+
|
|
189
|
+
.table__header {
|
|
190
|
+
font-weight: 400;
|
|
191
|
+
padding: 0;
|
|
192
|
+
text-align: left;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
//*
|
|
198
|
+
// The container around the rows that make up the body of the table.
|
|
199
|
+
|
|
200
|
+
.table__body {
|
|
201
|
+
// Striped rows!
|
|
202
|
+
> .table__row:nth-child(odd) > .table__cell {
|
|
203
|
+
background-color: color(gray-lighter);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
//*
|
|
210
|
+
// A row of table cells.
|
|
211
|
+
|
|
212
|
+
.table__row {
|
|
213
|
+
// Hide the overflow so that box shadows on persistant cells don't bleed
|
|
214
|
+
// between rows.
|
|
215
|
+
overflow: hidden;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
//*
|
|
221
|
+
// An individual table cell.
|
|
222
|
+
|
|
223
|
+
.table__cell {
|
|
224
|
+
position: relative;
|
|
225
|
+
@include z-index(cell, table);
|
|
226
|
+
vertical-align: top;
|
|
227
|
+
padding: half(default(spacing));
|
|
228
|
+
background-color: color(white);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
//*
|
|
232
|
+
// A table cell with center-aligned text.
|
|
233
|
+
|
|
234
|
+
.table__cell--centered {
|
|
235
|
+
text-align: center;
|
|
236
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<%
|
|
2
|
+
tablist.configure do |config|
|
|
3
|
+
config.defaults(manage_url?: false, size: :regular)
|
|
4
|
+
config.classes(base: "tablist")
|
|
5
|
+
|
|
6
|
+
config.conditional_classes(from: :size, large: { base: "tablist--large" })
|
|
7
|
+
config.conditional_classes(if: :manage_url?, base: "tablist--manages-url")
|
|
8
|
+
end
|
|
9
|
+
%>
|
|
10
|
+
|
|
11
|
+
<div class="<%= tablist.classes_for(:base) %>" role="tablist">
|
|
12
|
+
<%= capture(tablist, &tablist.block) %>
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import QueryString from "~utilities/query_string";
|
|
2
|
+
import Builder from "~utilities/builder";
|
|
3
|
+
import Cache from "~utilities/dom_cache";
|
|
4
|
+
|
|
5
|
+
const classes = {
|
|
6
|
+
root: "tablist",
|
|
7
|
+
tab: "tablist__tab",
|
|
8
|
+
panel: "tablist__panel"
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const variants = {
|
|
12
|
+
root: { manages_url: "tablist--manages-url" }
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const states = {
|
|
16
|
+
tab: { active: "tablist__tab--is-active" },
|
|
17
|
+
panel: { active: "tablist__panel--is-active" }
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
var Tablist, tab_click, panel_for_tab, tab_for_panel, tablist_for_node, a11y,
|
|
21
|
+
apply_activation_markup, remove_activation_markup, panel_containing_node;
|
|
22
|
+
|
|
23
|
+
//*
|
|
24
|
+
// Manages a click on a tab by finding the associated `Tablist` and activating
|
|
25
|
+
// the tab that was clicked on.
|
|
26
|
+
//
|
|
27
|
+
// @param {Object} event - The `click` event.
|
|
28
|
+
// @private
|
|
29
|
+
|
|
30
|
+
tab_click = (event) => {
|
|
31
|
+
var tablist;
|
|
32
|
+
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
|
|
35
|
+
tablist = Tablist.for(event.target);
|
|
36
|
+
if(!tablist) { return; }
|
|
37
|
+
tablist.activate_tab($(event.currentTarget).closest(`.${classes.tab}`)[0]);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
//*
|
|
41
|
+
// Finds the tab panel associated with the passed tab. The association is based
|
|
42
|
+
// on the ID of the tab panel matching the `href` of the tab.
|
|
43
|
+
//
|
|
44
|
+
// @param {HTMLElement} tab - The tab for which you want the associated panel.
|
|
45
|
+
// @private
|
|
46
|
+
//
|
|
47
|
+
// @returns {HTMLElement | null} The associated tab panel or, if no matching
|
|
48
|
+
// panel was found, `null`.
|
|
49
|
+
|
|
50
|
+
panel_for_tab = (tab) => {
|
|
51
|
+
return tab && document.getElementById(tab.getAttribute("href").replace("#", ""));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
//*
|
|
55
|
+
// Finds the tab associated with the passed panel. The association is based
|
|
56
|
+
// on the ID of the tab panel matching the `href` of the tab.
|
|
57
|
+
//
|
|
58
|
+
// @param {HTMLElement} tab - The tab for which you want the associated panel.
|
|
59
|
+
// @private
|
|
60
|
+
//
|
|
61
|
+
// @returns {HTMLElement | null} The associated tab or, if no matching panel
|
|
62
|
+
// was found, `null`.
|
|
63
|
+
|
|
64
|
+
tab_for_panel = (panel) => {
|
|
65
|
+
return panel && document.querySelector(`.${classes.tab}[href='#${panel.id}']`);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
//*
|
|
69
|
+
// Writes all of the required accessibility markup to the tablist and its
|
|
70
|
+
// subcomponents. This includes IDs for the tablist and its tabs/ panels,
|
|
71
|
+
// roles for the same, and the `aria-` associations between tabs and their
|
|
72
|
+
// corresponding panels.
|
|
73
|
+
//
|
|
74
|
+
// @param {HTMLElement} tablist - The root node of the tablist.
|
|
75
|
+
// @private
|
|
76
|
+
|
|
77
|
+
a11y = (() => {
|
|
78
|
+
var current_ids, id_for;
|
|
79
|
+
|
|
80
|
+
current_ids = {
|
|
81
|
+
[classes.root]: 1,
|
|
82
|
+
[classes.tab]: 1,
|
|
83
|
+
[classes.panel]: 1
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
id_for = (node) => {
|
|
87
|
+
var type = node.className.split(" ")[0];
|
|
88
|
+
return `${type}--${current_ids[type]++}`;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return (tablist) => {
|
|
92
|
+
var panel, tab_id, panel_id, tab;
|
|
93
|
+
|
|
94
|
+
tablist.id = tablist.id || id_for(tablist);
|
|
95
|
+
tablist.setAttribute("role", "tablist");
|
|
96
|
+
|
|
97
|
+
for(tab of Array.from(tablist.querySelectorAll(`.${classes.tab}`))) {
|
|
98
|
+
panel = panel_for_tab(tab);
|
|
99
|
+
if(!panel) { continue; }
|
|
100
|
+
|
|
101
|
+
tab_id = tab.id || id_for(tab);
|
|
102
|
+
panel_id = panel.id || id_for(panel);
|
|
103
|
+
|
|
104
|
+
tab.id = tab_id;
|
|
105
|
+
tab.setAttribute("role", "tab");
|
|
106
|
+
tab.setAttribute("aria-controls", panel_id);
|
|
107
|
+
tab.setAttribute("href", `#${panel_id}`);
|
|
108
|
+
|
|
109
|
+
panel.id = panel_id;
|
|
110
|
+
panel.setAttribute("role", "tab-panel");
|
|
111
|
+
panel.setAttribute("aria-labelledby", tab_id);
|
|
112
|
+
panel.setAttribute("aria-hidden", !panel.classList.contains(states.panel.active));
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
})();
|
|
116
|
+
|
|
117
|
+
apply_activation_markup = (node) => {
|
|
118
|
+
if(!node) { return; }
|
|
119
|
+
|
|
120
|
+
if(node.classList.contains(classes.tab)) {
|
|
121
|
+
node.classList.add(states.tab.active);
|
|
122
|
+
} else {
|
|
123
|
+
node.classList.add(states.panel.active);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
remove_activation_markup = (node) => {
|
|
128
|
+
if(!node) { return; }
|
|
129
|
+
|
|
130
|
+
if(node.classList.contains(classes.tab)) {
|
|
131
|
+
node.classList.remove(states.tab.active);
|
|
132
|
+
} else {
|
|
133
|
+
node.classList.remove(states.panel.active);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
panel_containing_node = (node) => {
|
|
138
|
+
return $(node).closest(`.${classes.panel}`)[0];
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
tablist_for_node = (node) => {
|
|
142
|
+
if(node.classList.contains(classes.panel)) {
|
|
143
|
+
node = tab_for_panel(node);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return $(node).closest(`.${classes.root}`)[0];
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
//*
|
|
150
|
+
// The constructor around a `Tablist` component. This constructor returns a very
|
|
151
|
+
// small API: only an `activate_tab` method is exposed, which will activate the
|
|
152
|
+
// passed tab in the tablist. This constructor will also ensure that all the
|
|
153
|
+
// aria properties and associations are hooked up correctly.
|
|
154
|
+
|
|
155
|
+
Tablist = (root) => {
|
|
156
|
+
var active_tab = root.querySelector(`.${states.tab.active}`),
|
|
157
|
+
active_panel = panel_for_tab(active_tab),
|
|
158
|
+
saved_tab, api, self;
|
|
159
|
+
|
|
160
|
+
a11y(root);
|
|
161
|
+
|
|
162
|
+
self = {
|
|
163
|
+
root,
|
|
164
|
+
id: root.id,
|
|
165
|
+
active_panel: panel_for_tab(active_tab),
|
|
166
|
+
manages_url: root.classList.contains(variants.root.manages_url)
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
api = {
|
|
170
|
+
//*
|
|
171
|
+
// Activates the passed tab, deactivating the currently-active tab, if there
|
|
172
|
+
// is one (and it is not the passed tab).
|
|
173
|
+
//
|
|
174
|
+
// @param {HTMLElement} tab - The tab to activate.
|
|
175
|
+
|
|
176
|
+
activate_tab(tab) { this.active_tab = tab; },
|
|
177
|
+
|
|
178
|
+
get active_tab() { return active_tab; },
|
|
179
|
+
set active_tab(tab) {
|
|
180
|
+
var panel = panel_for_tab(tab);
|
|
181
|
+
|
|
182
|
+
apply_activation_markup(tab);
|
|
183
|
+
apply_activation_markup(panel);
|
|
184
|
+
|
|
185
|
+
if(!tab || tab === active_tab) { return; }
|
|
186
|
+
|
|
187
|
+
remove_activation_markup(active_tab);
|
|
188
|
+
remove_activation_markup(active_panel);
|
|
189
|
+
|
|
190
|
+
active_tab = tab;
|
|
191
|
+
active_panel = panel;
|
|
192
|
+
|
|
193
|
+
if(this.manages_url && QueryString.get(this.id) !== tab.id) {
|
|
194
|
+
QueryString.set(this.id, tab.id);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
get active_panel() { return active_panel; },
|
|
199
|
+
set active_panel(panel) {
|
|
200
|
+
this.active_tab = panel_for_tab(panel);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
if(self.manages_url) {
|
|
205
|
+
saved_tab = QueryString.get(self.id);
|
|
206
|
+
if(saved_tab) { api.active_tab = document.getElementById(saved_tab); }
|
|
207
|
+
} else {
|
|
208
|
+
api.active_tab = active_tab;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return api;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
Tablist.for = (node) => {
|
|
215
|
+
var tablist_node = $(node).closest(`.${classes.root}`)[0],
|
|
216
|
+
containing_panel;
|
|
217
|
+
|
|
218
|
+
if(!tablist_node) {
|
|
219
|
+
containing_panel = node.classList.contains(classes.panel) ? node : panel_containing_node(node);
|
|
220
|
+
if(!containing_panel) { return false; }
|
|
221
|
+
tablist_node = tablist_for_node(containing_panel);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if(!tablist_node) { return false; }
|
|
225
|
+
return Cache(tablist_node).get(classes.root);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
Tablist.init = () => {
|
|
229
|
+
Builder.build_and_cache(Tablist, { name: classes.root });
|
|
230
|
+
$(document).on("click", `.${classes.tab}`, tab_click);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
Tablist.activate_panel_containing = (node) => {
|
|
234
|
+
var panel = $(node).closest(`.${classes.panel}`)[0],
|
|
235
|
+
tablist = Tablist.for(panel);
|
|
236
|
+
|
|
237
|
+
if(tablist) { tablist.active_tab = tab_for_panel(panel); }
|
|
238
|
+
return !!tablist;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
Tablist.is_in_active_panel = (node) => {
|
|
242
|
+
var panel = panel_containing_node(node);
|
|
243
|
+
return !!panel && panel.classList.contains(states.panel.active);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
export default Tablist;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// ___ ___
|
|
2
|
+
// ___ / /\ _____ ___ / /\ ___
|
|
3
|
+
// / /\ / /::\ / /::\ / /\ / /:/_ / /\
|
|
4
|
+
// / /:/ / /:/\:\ / /:/\:\ ___ ___ / /:/ / /:/ /\ / /:/
|
|
5
|
+
// / /:/ / /:/~/::\ / /:/~/::\/__/\ / /\/__/::\ / /:/ /::\ / /:/
|
|
6
|
+
// / /::\/__/:/ /:/\:\/__/:/ /:/\:\ \:\ / /:/\__\/\:\__/__/:/ /:/\:\/ /::\
|
|
7
|
+
// /__/:/\:\ \:\/:/__\/\ \:\/:/~/:/\ \:\ /:/ \ \:\/\ \:\/:/~/:/__/:/\:\
|
|
8
|
+
// \__\/ \:\ \::/ \ \::/ /:/ \ \:\/:/ \__\::/\ \::/ /:/\__\/ \:\
|
|
9
|
+
// \ \:\ \:\ \ \:\/:/ \ \::/ /__/:/ \__\/ /:/ \ \:\
|
|
10
|
+
// \__\/\ \:\ \ \::/ \__\/ \__\/ /__/:/ \__\/
|
|
11
|
+
// \__\/ \__\/ \__\/
|
|
12
|
+
|
|
13
|
+
//*
|
|
14
|
+
// @pattern Tablist
|
|
15
|
+
//
|
|
16
|
+
// Tablists are used to create groups of related content that is conditionally
|
|
17
|
+
// shown or hidden based on the selected tab. The JavaScript part of this
|
|
18
|
+
// components ensures that the required accessibility-related markup is added
|
|
19
|
+
// to the tabs, and a number of different styles are available depending on
|
|
20
|
+
// the context in which the tabs are being used.
|
|
21
|
+
//
|
|
22
|
+
// @since 1.0.0
|
|
23
|
+
|
|
24
|
+
//*
|
|
25
|
+
// The container for a set of tabs. While panels and tabs both use `tablist`
|
|
26
|
+
// as their base component, only `tablist__tab`s are child nodes of this
|
|
27
|
+
// component; `tablist__panel`s (and their container) are separate from the
|
|
28
|
+
// document to allow tabs to move around the page independently of the content
|
|
29
|
+
// they actually activate.
|
|
30
|
+
//
|
|
31
|
+
// The `tablist--manages-url` variant is unique in that it has no visual
|
|
32
|
+
// differences, but will preserve the selected tab via a query string parameter
|
|
33
|
+
// and restore the selected tab on subsequent page loads. To add this
|
|
34
|
+
// functionality, simply pass `true` for the `:manage_url` option of the
|
|
35
|
+
// `docks_tablist` view helper.
|
|
36
|
+
//
|
|
37
|
+
// @helper docks_tablist
|
|
38
|
+
|
|
39
|
+
.tablist {
|
|
40
|
+
// box model
|
|
41
|
+
margin: 0;
|
|
42
|
+
padding: 0;
|
|
43
|
+
display: flex;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
padding: half(default(spacing));
|
|
46
|
+
margin-right: negative(half(default(spacing)));
|
|
47
|
+
|
|
48
|
+
// backdrop
|
|
49
|
+
list-style: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//*
|
|
53
|
+
// A larger set of tabs (both in terms of the font size of the tabs and the
|
|
54
|
+
// padding within each tab).
|
|
55
|
+
//
|
|
56
|
+
// @set_by :size (:large)
|
|
57
|
+
|
|
58
|
+
.tablist--large {
|
|
59
|
+
margin: double(default(spacing)) 0;
|
|
60
|
+
|
|
61
|
+
> .tablist__tab {
|
|
62
|
+
@include font-size(tablist--large);
|
|
63
|
+
line-height: 1;
|
|
64
|
+
padding: default(spacing) multiply(default(spacing), 2.5) multiply(default(spacing), 1.2);
|
|
65
|
+
border: none !important;
|
|
66
|
+
opacity: 1 !important;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
> .tablist__tab--is-active {
|
|
70
|
+
background-color: ui-color(gray, light);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//*
|
|
75
|
+
// A variation of the tablist that forces the JavaScript to preserve the
|
|
76
|
+
// selected tab and reload that tab on subsequent page loads.
|
|
77
|
+
//
|
|
78
|
+
// @demo_type none
|
|
79
|
+
// @set_by :manage_url
|
|
80
|
+
|
|
81
|
+
.tablist--manages-url {}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
//*
|
|
87
|
+
// A single tab in the tablist. Tabs will be a relatively light color by
|
|
88
|
+
// default with progressively darker shades used on `:focus`/`:hover` and when
|
|
89
|
+
// `:active`.
|
|
90
|
+
//
|
|
91
|
+
// Tabs should still work even when there is no JavaScript or CSS. To make this
|
|
92
|
+
// work, ensure that each `tablist__tab` is an `a` tag with an `href` that
|
|
93
|
+
// points to the `id` of the relevant `tablist__panel`. Likewise, the `id`s of
|
|
94
|
+
// the tab and panel should match up vai the `aria-controls` and
|
|
95
|
+
// `aria-labelledby` properties. The JavaScript component, if run, will
|
|
96
|
+
// guarantee all of these associations.
|
|
97
|
+
//
|
|
98
|
+
// @helper docks_tablist_tab
|
|
99
|
+
|
|
100
|
+
.tablist__tab {
|
|
101
|
+
// box model
|
|
102
|
+
display: inline-block;
|
|
103
|
+
padding: 0 default(control-padding);
|
|
104
|
+
|
|
105
|
+
// backdrop
|
|
106
|
+
opacity: 0.3;
|
|
107
|
+
overflow: hidden;
|
|
108
|
+
border: 1px solid transparent;
|
|
109
|
+
border-radius: default(border-radius);
|
|
110
|
+
transition: opacity 0.3s ease, border-color 0.3s ease;
|
|
111
|
+
|
|
112
|
+
// type
|
|
113
|
+
@include font-size(control);
|
|
114
|
+
line-height: default(control-size);
|
|
115
|
+
color: ui-color(gray, darker);
|
|
116
|
+
text-align: center;
|
|
117
|
+
text-decoration: none;
|
|
118
|
+
white-space: nowrap;
|
|
119
|
+
text-overflow: ellipsis;
|
|
120
|
+
|
|
121
|
+
&:focus,
|
|
122
|
+
&:hover {
|
|
123
|
+
outline: none;
|
|
124
|
+
opacity: 0.5;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
> .icon {
|
|
128
|
+
height: double(default(spacing));
|
|
129
|
+
width: double(default(spacing));
|
|
130
|
+
@include icon--recolor(gray, dark);
|
|
131
|
+
stroke-width: 3px;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//*
|
|
136
|
+
// The variation added to the tab whose corresponding tab is currently
|
|
137
|
+
// visible. This class can either be applied manually by setting the `:active?`
|
|
138
|
+
// argument to the helper method to `true` or by clicking on the correct tab
|
|
139
|
+
// (which does all the required attribute manipulations through the JavaScript
|
|
140
|
+
// component).
|
|
141
|
+
//
|
|
142
|
+
// @demo_type none
|
|
143
|
+
// @set_by :active?
|
|
144
|
+
|
|
145
|
+
.tablist__tab--is-active {
|
|
146
|
+
&, &:hover, &:focus {
|
|
147
|
+
border-color: ui-color(gray, darker);
|
|
148
|
+
opacity: 1;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
//*
|
|
153
|
+
// The text within a tab. This container is required in order for the text and
|
|
154
|
+
// (optional) icon to be above one another.
|
|
155
|
+
|
|
156
|
+
.tablist__tab__text {
|
|
157
|
+
display: block;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
//*
|
|
163
|
+
// A panel that contains the content that should be shown when the associated
|
|
164
|
+
// tab is active.
|
|
165
|
+
//
|
|
166
|
+
// @helper docks_tablist_panel
|
|
167
|
+
|
|
168
|
+
.tablist__panel {
|
|
169
|
+
display: none;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
//*
|
|
173
|
+
// A state indicating that the associated tab is active and the contents of
|
|
174
|
+
// this panel should be made visible. There is no animation when switching
|
|
175
|
+
// between tabs — they simply pop in and out of view.
|
|
176
|
+
//
|
|
177
|
+
// @demo_type none
|
|
178
|
+
// @set_by :active?
|
|
179
|
+
|
|
180
|
+
.tablist__panel--is-active {
|
|
181
|
+
display: block;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
//*
|
|
187
|
+
// A container around all of the panels for a tablist. This container
|
|
188
|
+
// technically does nothing, but is a nice way to isolate a set of tab panels
|
|
189
|
+
// from the surrounding content.
|
|
190
|
+
|
|
191
|
+
.tablist__panel-container {}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<%
|
|
2
|
+
panel.configure do |config|
|
|
3
|
+
config.defaults active?: false,
|
|
4
|
+
id: "panel",
|
|
5
|
+
tab_id: "tab"
|
|
6
|
+
|
|
7
|
+
config.classes(base: "tablist__panel")
|
|
8
|
+
config.conditional_classes(if: :active?, base: "tablist__panel--is-active")
|
|
9
|
+
end
|
|
10
|
+
%>
|
|
11
|
+
|
|
12
|
+
<div class="<%= panel.classes_for(:base) %>" role="tab-panel" id="<%= panel.id %>" aria-hidden="<%= !panel.active? %>" aria-labelledby="<%= panel.tab_id %>">
|
|
13
|
+
<%= capture(panel, &panel.block) %>
|
|
14
|
+
</div>
|