white-rabbit 0.1.0

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.
@@ -0,0 +1,11 @@
1
+ body {
2
+ background-color: var(--meka-body);
3
+ color: var(--meka-accent);
4
+ font-family: var(--monospace);
5
+ font-size: var(--font-size-base);
6
+ height: 100%;
7
+ line-height: 1.6;
8
+ margin: 0 auto;
9
+ max-width: 1280px;
10
+ padding: var(--spacing-4);
11
+ }
data/_sass/_grid.scss ADDED
@@ -0,0 +1,14 @@
1
+ .grid {
2
+ display: grid;
3
+ grid-gap: var(--spacing-5) var(--spacing-3);
4
+ grid-template-columns: auto;
5
+ grid-template-rows: auto;
6
+ }
7
+
8
+ .grid-12 .grid-item {
9
+ grid-column: span 12;
10
+ }
11
+
12
+ .grid-8 .grid-item {
13
+ grid-column: span 8;
14
+ }
@@ -0,0 +1,45 @@
1
+ .site-header,
2
+ .site-footer {
3
+ padding: var(--spacing-4);
4
+ }
5
+
6
+ .site-footer {
7
+ color: var(--dva-secondary-base);
8
+ text-align: center;
9
+ }
10
+
11
+ // navigation
12
+ .site-header .navigation {
13
+ display: flex;
14
+ align-items: center;
15
+ }
16
+
17
+ .site-header .logo .header,
18
+ .site-header .logo .subheader {
19
+ display: block;
20
+ }
21
+
22
+ .site-header .logo .header {
23
+ font-size: var(--font-size-5);
24
+ font-weight: 700;
25
+ }
26
+
27
+ .site-header .logo .subheader {
28
+ font-size: var(--font-size-2);
29
+ font-weight: 400;
30
+ margin-top: calc(-1*var(--spacing-1));
31
+ position: relative;
32
+ }
33
+
34
+ .site-header .links {
35
+ flex-grow: 1;
36
+ text-align: right;
37
+ }
38
+
39
+ .site-header .link {
40
+ display: inline-block;
41
+ }
42
+
43
+ .site-header .link:not(:last-child) {
44
+ margin-right: var(--spacing-3);
45
+ }
@@ -0,0 +1,87 @@
1
+ /*! minireset.css v0.0.3 | MIT License | github.com/jgthms/minireset.css */
2
+ html {
3
+ background-color: var(--meka-accent);
4
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 304 304' width='304' height='304'%3E%3Cpath fill='%23ffffff' fill-opacity='0.025' d='M44.1 224a5 5 0 1 1 0 2H0v-2h44.1zm160 48a5 5 0 1 1 0 2H82v-2h122.1zm57.8-46a5 5 0 1 1 0-2H304v2h-42.1zm0 16a5 5 0 1 1 0-2H304v2h-42.1zm6.2-114a5 5 0 1 1 0 2h-86.2a5 5 0 1 1 0-2h86.2zm-256-48a5 5 0 1 1 0 2H0v-2h12.1zm185.8 34a5 5 0 1 1 0-2h86.2a5 5 0 1 1 0 2h-86.2zM258 12.1a5 5 0 1 1-2 0V0h2v12.1zm-64 208a5 5 0 1 1-2 0v-54.2a5 5 0 1 1 2 0v54.2zm48-198.2V80h62v2h-64V21.9a5 5 0 1 1 2 0zm16 16V64h46v2h-48V37.9a5 5 0 1 1 2 0zm-128 96V208h16v12.1a5 5 0 1 1-2 0V210h-16v-76.1a5 5 0 1 1 2 0zm-5.9-21.9a5 5 0 1 1 0 2H114v48H85.9a5 5 0 1 1 0-2H112v-48h12.1zm-6.2 130a5 5 0 1 1 0-2H176v-74.1a5 5 0 1 1 2 0V242h-60.1zm-16-64a5 5 0 1 1 0-2H114v48h10.1a5 5 0 1 1 0 2H112v-48h-10.1zM66 284.1a5 5 0 1 1-2 0V274H50v30h-2v-32h18v12.1zM236.1 176a5 5 0 1 1 0 2H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30a5 5 0 1 1 0-2H274v44.1a5 5 0 1 1-2 0V146h-10.1zm-64 96a5 5 0 1 1 0-2H208v-80h16v-14h-42.1a5 5 0 1 1 0-2H226v18h-16v80h-12.1zm86.2-210a5 5 0 1 1 0 2H272V0h2v32h10.1zM98 101.9V146H53.9a5 5 0 1 1 0-2H96v-42.1a5 5 0 1 1 2 0zM53.9 34a5 5 0 1 1 0-2H80V0h2v34H53.9zm60.1 3.9V66H82v64H69.9a5 5 0 1 1 0-2H80V64h32V37.9a5 5 0 1 1 2 0zM101.9 82a5 5 0 1 1 0-2H128V37.9a5 5 0 1 1 2 0V82h-28.1zm16-64a5 5 0 1 1 0-2H146v44.1a5 5 0 1 1-2 0V18h-26.1zm102.2 270a5 5 0 1 1 0 2H98v14h-2v-16h124.1zM242 149.9V160h16v34h-16v62h48v48h-2v-46h-48v-66h16v-30h-16v-12.1a5 5 0 1 1 2 0zM53.9 18a5 5 0 1 1 0-2H64V2H48V0h18v18H53.9zm112 32a5 5 0 1 1 0-2H192V0h50v2h-48v48h-28.1zm-48-48a5 5 0 0 1-9.8-2h2.07a3 3 0 1 0 5.66 0H178v34h-18V21.9a5 5 0 1 1 2 0V32h14V2h-58.1zm0 96a5 5 0 1 1 0-2H137l32-32h39V21.9a5 5 0 1 1 2 0V66h-40.17l-32 32H117.9zm28.1 90.1a5 5 0 1 1-2 0v-76.51L175.59 80H224V21.9a5 5 0 1 1 2 0V82h-49.59L146 112.41v75.69zm16 32a5 5 0 1 1-2 0v-99.51L184.59 96H300.1a5 5 0 0 1 3.9-3.9v2.07a3 3 0 0 0 0 5.66v2.07a5 5 0 0 1-3.9-3.9H185.41L162 121.41v98.69zm-144-64a5 5 0 1 1-2 0v-3.51l48-48V48h32V0h2v50H66v55.41l-48 48v2.69zM50 53.9v43.51l-48 48V208h26.1a5 5 0 1 1 0 2H0v-65.41l48-48V53.9a5 5 0 1 1 2 0zm-16 16V89.41l-34 34v-2.82l32-32V69.9a5 5 0 1 1 2 0zM12.1 32a5 5 0 1 1 0 2H9.41L0 43.41V40.6L8.59 32h3.51zm265.8 18a5 5 0 1 1 0-2h18.69l7.41-7.41v2.82L297.41 50H277.9zm-16 160a5 5 0 1 1 0-2H288v-71.41l16-16v2.82l-14 14V210h-28.1zm-208 32a5 5 0 1 1 0-2H64v-22.59L40.59 194H21.9a5 5 0 1 1 0-2H41.41L66 216.59V242H53.9zm150.2 14a5 5 0 1 1 0 2H96v-56.6L56.6 162H37.9a5 5 0 1 1 0-2h19.5L98 200.6V256h106.1zm-150.2 2a5 5 0 1 1 0-2H80v-46.59L48.59 178H21.9a5 5 0 1 1 0-2H49.41L82 208.59V258H53.9zM34 39.8v1.61L9.41 66H0v-2h8.59L32 40.59V0h2v39.8zM2 300.1a5 5 0 0 1 3.9 3.9H3.83A3 3 0 0 0 0 302.17V256h18v48h-2v-46H2v42.1zM34 241v63h-2v-62H0v-2h34v1zM17 18H0v-2h16V0h2v18h-1zm273-2h14v2h-16V0h2v16zm-32 273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1A5.02 5.02 0 0 1 6 97a5 5 0 0 1-6 4.9v-2.07a3 3 0 1 0 0-5.66V92.1zM80 272h2v32h-2v-32zm37.9 32h-2.07a3 3 0 0 0-5.66 0h-2.07a5 5 0 0 1 9.8 0zM5.9 0A5.02 5.02 0 0 1 0 5.9V3.83A3 3 0 0 0 3.83 0H5.9zm294.2 0h2.07A3 3 0 0 0 304 3.83V5.9a5 5 0 0 1-3.9-5.9zm3.9 300.1v2.07a3 3 0 0 0-1.83 1.83h-2.07a5 5 0 0 1 3.9-3.9zM97 100a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-48 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 96a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-144a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM49 36a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM33 68a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 240a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm80-176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm112 176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 180a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 84a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6z'%3E%3C/path%3E%3C/svg%3E");
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ html,
9
+ body,
10
+ p,
11
+ ol,
12
+ ul,
13
+ li,
14
+ dl,
15
+ dt,
16
+ dd,
17
+ blockquote,
18
+ figure,
19
+ fieldset,
20
+ legend,
21
+ textarea,
22
+ pre,
23
+ iframe,
24
+ hr,
25
+ h1,
26
+ h2,
27
+ h3,
28
+ h4,
29
+ h5,
30
+ h6 {
31
+ margin: 0;
32
+ padding: 0;
33
+ }
34
+
35
+ h1,
36
+ h2,
37
+ h3,
38
+ h4,
39
+ h5,
40
+ h6 {
41
+ font-weight: normal;
42
+ font-size: 100%;
43
+ }
44
+
45
+ ul {
46
+ list-style: none;
47
+ }
48
+
49
+ button,
50
+ input,
51
+ select,
52
+ textarea {
53
+ margin: 0;
54
+ }
55
+
56
+ *,
57
+ *:before,
58
+ *:after {
59
+ box-sizing: inherit;
60
+ }
61
+
62
+ img,
63
+ embed,
64
+ iframe,
65
+ object,
66
+ audio,
67
+ video {
68
+ height: auto;
69
+ max-width: 100%;
70
+ width: 100%;
71
+ vertical-align: middle;
72
+ }
73
+
74
+ iframe {
75
+ border: 0;
76
+ }
77
+
78
+ table {
79
+ border-collapse: collapse;
80
+ border-spacing: 0;
81
+ }
82
+
83
+ td,
84
+ th {
85
+ padding: 0;
86
+ text-align: left;
87
+ }
@@ -0,0 +1,10 @@
1
+ a {
2
+ color: var(--meka-accent);
3
+ font-weight: 700;
4
+ text-decoration: none;
5
+ transition: 150ms ease-in;
6
+ }
7
+
8
+ a:hover {
9
+ color: var(--meka-matrix);
10
+ }
data/_sass/app.scss ADDED
@@ -0,0 +1,13 @@
1
+ @charset "utf-8";
2
+
3
+ @import "custom-properties";
4
+ @import "resets";
5
+
6
+ @import "blocks";
7
+ @import "content";
8
+ @import "general";
9
+ @import "grid";
10
+ @import "navigation";
11
+ @import "typography";
12
+
13
+ @import "third-party/tabby";
@@ -0,0 +1,71 @@
1
+ /*!
2
+ * Tabby v11.2.0: Simple, mobile-first toggle tabs.
3
+ * (c) 2016 Chris Ferdinandi
4
+ * MIT License
5
+ * http://github.com/cferdinandi/tabby
6
+ */
7
+
8
+ /**
9
+ * Tab content
10
+ */
11
+
12
+ /* line 4, /Users/cferdinandi/Sites/tabby/src/sass/components/_tabby.scss */
13
+ .js-tabby .tabs-pane {
14
+ border: 0;
15
+ clip: rect(0 0 0 0);
16
+ height: 1px;
17
+ margin: -1px;
18
+ opacity: 0;
19
+ overflow: hidden;
20
+ padding: 0;
21
+ position: absolute;
22
+ transform: translateY(40px);
23
+ transition: opacity 250ms ease-in, transform 300ms ease-in;
24
+ }
25
+
26
+ /* line 14, /Users/cferdinandi/Sites/tabby/src/sass/components/_tabby.scss */
27
+ .js-tabby .tabs-pane.active {
28
+ clip: auto;
29
+ height: auto;
30
+ margin: 0;
31
+ opacity: 1;
32
+ overflow: visible;
33
+ position: static;
34
+ transform: translateY(0px);
35
+ }
36
+
37
+ /* line 23, /Users/cferdinandi/Sites/tabby/src/sass/components/_tabby.scss */
38
+ .js-tabby .tabs-pane:focus {
39
+ outline: none;
40
+ }
41
+
42
+ // custom styling
43
+ .tabs {
44
+ margin-bottom: var(--spacing-4);
45
+ text-align: center;
46
+ }
47
+
48
+ .tabs li {
49
+ display: inline-block;
50
+ font-size: var(--font-size-1);
51
+ margin-right: var(--spacing-3);
52
+ }
53
+
54
+ .tabs a {
55
+ background-color: var(--meka-body);
56
+ color: var(--meka-accent);
57
+ padding: var(--spacing-2) var(--spacing-3);
58
+ }
59
+
60
+ .tabs a:hover,
61
+ .tabs .active a {
62
+ color: var(--meka-body);
63
+ }
64
+
65
+ .tabs a:hover {
66
+ background-color: var(--dva-secondary-dark);
67
+ }
68
+
69
+ .tabs .active a {
70
+ background-color: var(--meka-matrix);
71
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,518 @@
1
+ /*!
2
+ * Tabby v11.2.0: Simple, mobile-first toggle tabs.
3
+ * (c) 2016 Chris Ferdinandi
4
+ * MIT License
5
+ * http://github.com/cferdinandi/tabby
6
+ */
7
+
8
+ (function (root, factory) {
9
+ if (typeof define === 'function' && define.amd) {
10
+ define([], factory(root));
11
+ } else if (typeof exports === 'object') {
12
+ module.exports = factory(root);
13
+ } else {
14
+ root.tabby = factory(root);
15
+ }
16
+ })(typeof global !== 'undefined' ? global : this.window || this.global, (function (root) {
17
+
18
+ 'use strict';
19
+
20
+ //
21
+ // Variables
22
+ //
23
+
24
+ var tabby = {}; // Object for public APIs
25
+ var supports = 'querySelector' in document && 'addEventListener' in root && 'classList' in document.createElement('_') && 'onhashchange' in root; // Feature test
26
+ var settings, tab;
27
+
28
+ // Default settings
29
+ var defaults = {
30
+ selectorToggle: '[data-tab]',
31
+ selectorToggleGroup: '[data-tabs]',
32
+ selectorContent: '[data-tabs-pane]',
33
+ selectorContentGroup: '[data-tabs-content]',
34
+ toggleActiveClass: 'active',
35
+ contentActiveClass: 'active',
36
+ initClass: 'js-tabby',
37
+ stopVideo: true,
38
+ callback: function () {}
39
+ };
40
+
41
+
42
+ //
43
+ // Methods
44
+ //
45
+
46
+ /**
47
+ * A simple forEach() implementation for Arrays, Objects and NodeLists
48
+ * @private
49
+ * @param {Array|Object|NodeList} collection Collection of items to iterate
50
+ * @param {Function} callback Callback function for each iteration
51
+ * @param {Array|Object|NodeList} scope Object/NodeList/Array that forEach is iterating over (aka `this`)
52
+ */
53
+ var forEach = function (collection, callback, scope) {
54
+ if (Object.prototype.toString.call(collection) === '[object Object]') {
55
+ for (var prop in collection) {
56
+ if (Object.prototype.hasOwnProperty.call(collection, prop)) {
57
+ callback.call(scope, collection[prop], prop, collection);
58
+ }
59
+ }
60
+ } else {
61
+ for (var i = 0, len = collection.length; i < len; i++) {
62
+ callback.call(scope, collection[i], i, collection);
63
+ }
64
+ }
65
+ };
66
+
67
+ /**
68
+ * Merge defaults with user options
69
+ * @private
70
+ * @param {Object} defaults Default settings
71
+ * @param {Object} options User options
72
+ * @returns {Object} Merged values of defaults and options
73
+ */
74
+ var extend = function () {
75
+
76
+ // Variables
77
+ var extended = {};
78
+ var deep = false;
79
+ var i = 0;
80
+ var length = arguments.length;
81
+
82
+ // Check if a deep merge
83
+ if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') {
84
+ deep = arguments[0];
85
+ i++;
86
+ }
87
+
88
+ // Merge the object into the extended object
89
+ var merge = function (obj) {
90
+ for (var prop in obj) {
91
+ if (Object.prototype.hasOwnProperty.call(obj, prop)) {
92
+ // If deep merge and property is an object, merge properties
93
+ if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
94
+ extended[prop] = extend(true, extended[prop], obj[prop]);
95
+ } else {
96
+ extended[prop] = obj[prop];
97
+ }
98
+ }
99
+ }
100
+ };
101
+
102
+ // Loop through each object and conduct a merge
103
+ for (; i < length; i++) {
104
+ var obj = arguments[i];
105
+ merge(obj);
106
+ }
107
+
108
+ return extended;
109
+
110
+ };
111
+
112
+ /**
113
+ * Get the closest matching element up the DOM tree.
114
+ * @private
115
+ * @param {Element} elem Starting element
116
+ * @param {String} selector Selector to match against
117
+ * @return {Boolean|Element} Returns null if not match found
118
+ */
119
+ var getClosest = function (elem, selector) {
120
+
121
+ // Element.matches() polyfill
122
+ if (!Element.prototype.matches) {
123
+ Element.prototype.matches =
124
+ Element.prototype.matchesSelector ||
125
+ Element.prototype.mozMatchesSelector ||
126
+ Element.prototype.msMatchesSelector ||
127
+ Element.prototype.oMatchesSelector ||
128
+ Element.prototype.webkitMatchesSelector ||
129
+ function (s) {
130
+ var matches = (this.document || this.ownerDocument).querySelectorAll(s),
131
+ i = matches.length;
132
+ while (--i >= 0 && matches.item(i) !== this) {}
133
+ return i > -1;
134
+ };
135
+ }
136
+
137
+ // Get closest match
138
+ for (; elem && elem !== document; elem = elem.parentNode) {
139
+ if (elem.matches(selector)) return elem;
140
+ }
141
+
142
+ return null;
143
+
144
+ };
145
+
146
+ /**
147
+ * Escape special characters for use with querySelector
148
+ * @public
149
+ * @param {String} id The anchor ID to escape
150
+ * @author Mathias Bynens
151
+ * @link https://github.com/mathiasbynens/CSS.escape
152
+ */
153
+ var escapeCharacters = function (id) {
154
+
155
+ // Remove leading hash
156
+ if (id.charAt(0) === '#') {
157
+ id = id.substr(1);
158
+ }
159
+
160
+ var string = String(id);
161
+ var length = string.length;
162
+ var index = -1;
163
+ var codeUnit;
164
+ var result = '';
165
+ var firstCodeUnit = string.charCodeAt(0);
166
+ while (++index < length) {
167
+ codeUnit = string.charCodeAt(index);
168
+ // Note: there’s no need to special-case astral symbols, surrogate
169
+ // pairs, or lone surrogates.
170
+
171
+ // If the character is NULL (U+0000), then throw an
172
+ // `InvalidCharacterError` exception and terminate these steps.
173
+ if (codeUnit === 0x0000) {
174
+ throw new InvalidCharacterError(
175
+ 'Invalid character: the input contains U+0000.'
176
+ );
177
+ }
178
+
179
+ if (
180
+ // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
181
+ // U+007F, […]
182
+ (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
183
+ // If the character is the first character and is in the range [0-9]
184
+ // (U+0030 to U+0039), […]
185
+ (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
186
+ // If the character is the second character and is in the range [0-9]
187
+ // (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
188
+ (
189
+ index === 1 &&
190
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
191
+ firstCodeUnit === 0x002D
192
+ )
193
+ ) {
194
+ // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
195
+ result += '\\' + codeUnit.toString(16) + ' ';
196
+ continue;
197
+ }
198
+
199
+ // If the character is not handled by one of the above rules and is
200
+ // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
201
+ // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
202
+ // U+005A), or [a-z] (U+0061 to U+007A), […]
203
+ if (
204
+ codeUnit >= 0x0080 ||
205
+ codeUnit === 0x002D ||
206
+ codeUnit === 0x005F ||
207
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
208
+ codeUnit >= 0x0041 && codeUnit <= 0x005A ||
209
+ codeUnit >= 0x0061 && codeUnit <= 0x007A
210
+ ) {
211
+ // the character itself
212
+ result += string.charAt(index);
213
+ continue;
214
+ }
215
+
216
+ // Otherwise, the escaped character.
217
+ // http://dev.w3.org/csswg/cssom/#escape-a-character
218
+ result += '\\' + string.charAt(index);
219
+
220
+ }
221
+
222
+ return '#' + result;
223
+
224
+ };
225
+
226
+ /**
227
+ * Stop YouTube, Vimeo, and HTML5 videos from playing when leaving the slide
228
+ * @private
229
+ * @param {Element} content The content container the video is in
230
+ * @param {String} activeClass The class asigned to expanded content areas
231
+ */
232
+ var stopVideos = function (content, settings) {
233
+
234
+ // Check if stop video enabled
235
+ if (!settings.stopVideo) return;
236
+
237
+ // Only run if content container is closed
238
+ if (content.classList.contains(settings.contentActiveClass)) return;
239
+
240
+ // Check if the video is an iframe or HTML5 video
241
+ var iframe = content.querySelector('iframe');
242
+ var video = content.querySelector('video');
243
+
244
+ // Stop the video
245
+ if (iframe) {
246
+ var iframeSrc = iframe.src;
247
+ iframe.src = iframeSrc;
248
+ }
249
+ if (video) {
250
+ video.pause();
251
+ }
252
+
253
+ };
254
+
255
+ /**
256
+ * Add focus to tab
257
+ * @private
258
+ * @param {node} tab The content to bring into focus
259
+ * @param {object} settings Options
260
+ */
261
+ var adjustFocus = function (tab, settings) {
262
+
263
+ if (tab.hasAttribute('data-tab-no-focus')) return;
264
+
265
+ // If tab is closed, remove tabindex
266
+ if (!tab.classList.contains(settings.contentActiveClass)) {
267
+ if (tab.hasAttribute('data-tab-focused')) {
268
+ tab.removeAttribute('tabindex');
269
+ }
270
+ return;
271
+ }
272
+
273
+ // Get current position on the page
274
+ var position = {
275
+ x: root.pageXOffset,
276
+ y: root.pageYOffset
277
+ };
278
+
279
+ // Set focus and reset position to account for page jump on focus
280
+ tab.focus();
281
+ if (document.activeElement.id !== tab.id) {
282
+ tab.setAttribute('tabindex', '-1');
283
+ tab.setAttribute('data-tab-focused', true);
284
+ tab.focus();
285
+ }
286
+ root.scrollTo(position.x, position.y);
287
+
288
+ };
289
+
290
+ /**
291
+ * Toggle tab toggle active state
292
+ * @private
293
+ * @param {Node} toggle The toggle element
294
+ * @param {Object} settings
295
+ */
296
+ var toggleToggles = function (toggle, settings) {
297
+
298
+ // Variables
299
+ var toggleGroup = getClosest(toggle, settings.selectorToggleGroup); // The parent for the toggle group
300
+ if (!toggleGroup) return;
301
+ var toggles = toggleGroup.querySelectorAll(settings.selectorToggle); // The toggles in the group
302
+ var toggleList;
303
+
304
+ // Show or hide each toggle
305
+ // @todo Start here
306
+ forEach(toggles, (function (item) {
307
+
308
+ // If this is the selected toggle, activate it
309
+ if (item.hash === toggle.hash) {
310
+
311
+ // Add active class
312
+ item.classList.add(settings.toggleActiveClass);
313
+
314
+ // If toggle is a list item, activate <li> element, too
315
+ toggleList = getClosest(item, 'li');
316
+ if (toggleList) {
317
+ toggleList.classList.add(settings.toggleActiveClass);
318
+ }
319
+
320
+ return;
321
+
322
+ }
323
+
324
+ // Otherwise, deactivate it
325
+ item.classList.remove(settings.toggleActiveClass);
326
+ toggleList = getClosest(item, 'li');
327
+ if (toggleList) {
328
+ toggleList.classList.remove(settings.toggleActiveClass);
329
+ }
330
+
331
+ }));
332
+
333
+ };
334
+
335
+ /**
336
+ * Toggle tab active state
337
+ * @private
338
+ * @param {String} tabID The ID of the tab to activate
339
+ * @param {Object} settings
340
+ */
341
+ var toggleTabs = function (tabID, settings) {
342
+
343
+ // Variables
344
+ var tab = document.querySelector(escapeCharacters(tabID)); // The selected tab
345
+ if (!tab) return;
346
+ var tabGroup = getClosest(tab, settings.selectorContentGroup); // The parent for the tab group
347
+ if (!tabGroup) return;
348
+ var tabs = tabGroup.querySelectorAll(settings.selectorContent); // The tabs in the group
349
+
350
+ // Show or hide each tab
351
+ forEach(tabs, (function (tab) {
352
+
353
+ // If this is the selected tab, show it
354
+ if (tab.id === tabID.substring(1)) {
355
+ tab.classList.add(settings.contentActiveClass);
356
+ adjustFocus(tab, settings);
357
+ return;
358
+ }
359
+
360
+ // Otherwise, hide it
361
+ tab.classList.remove(settings.contentActiveClass);
362
+ stopVideos(tab, settings);
363
+ adjustFocus(tab, settings);
364
+
365
+ }));
366
+
367
+ };
368
+
369
+ /**
370
+ * Show a tab and hide all others
371
+ * @public
372
+ * @param {Element} toggle The element that toggled the show tab event
373
+ * @param {String} tabID The ID of the tab to show
374
+ * @param {Object} options
375
+ */
376
+ tabby.toggleTab = function (tabID, toggle, options) {
377
+
378
+ // Selectors and variables
379
+ var localSettings = extend(settings || defaults, options || {}); // Merge user options with defaults
380
+ var tabs = document.querySelectorAll(escapeCharacters(tabID)); // Get tab content
381
+
382
+ // Toggle visibility of the toggles and tabs
383
+ toggleTabs(tabID, localSettings);
384
+ if (toggle) {
385
+ toggleToggles(toggle, localSettings);
386
+ }
387
+
388
+ // Run callbacks after toggling tab
389
+ localSettings.callback(tabs, toggle);
390
+
391
+ };
392
+
393
+ /**
394
+ * Handle has change event
395
+ * @private
396
+ */
397
+ var hashChangeHandler = function (event) {
398
+
399
+ // Get hash from URL
400
+ var hash = root.location.hash;
401
+
402
+ // If clicked tab is cached, reset it's ID
403
+ if (tab) {
404
+ tab.id = tab.getAttribute('data-tab-id');
405
+ tab = null;
406
+ }
407
+
408
+ // If there's a URL hash, activate tab with matching ID
409
+ if (!hash) return;
410
+ var toggle = document.querySelector(settings.selectorToggle + '[href*="' + hash + '"]');
411
+ tabby.toggleTab(hash, toggle);
412
+
413
+ };
414
+
415
+ /**
416
+ * Handle toggle click events
417
+ * @private
418
+ */
419
+ var clickHandler = function (event) {
420
+
421
+ // Don't run if right-click or command/control + click
422
+ if (event.button !== 0 || event.metaKey || event.ctrlKey) return;
423
+
424
+ // Check if event target is a tab toggle
425
+ var toggle = getClosest(event.target, settings.selectorToggle);
426
+ if (!toggle || !toggle.hash) return;
427
+
428
+ // Don't run if toggle points to currently open tab
429
+ if (toggle.hash === root.location.hash) {
430
+ event.preventDefault();
431
+ return;
432
+ }
433
+
434
+ // Get the tab content
435
+ tab = document.querySelector(toggle.hash);
436
+
437
+ // If tab content exists, save the ID as a data attribute and remove it (prevents scroll jump)
438
+ if (!tab) return;
439
+ tab.setAttribute('data-tab-id', tab.id);
440
+ tab.id = '';
441
+
442
+ };
443
+
444
+ /**
445
+ * Handle content focus events
446
+ * @private
447
+ */
448
+ var focusHandler = function (event) {
449
+
450
+ // Only run if the focused content is in a tab
451
+ tab = getClosest(event.target, settings.selectorContent);
452
+ if (!tab) return;
453
+
454
+ // Don't run if the content area is already open
455
+ if (tab.classList.contains(settings.contentActiveClass)) return;
456
+
457
+ // Store tab ID to variable and remove it from the tab
458
+ var hash = tab.id;
459
+ tab.setAttribute('data-tab-id', hash);
460
+ tab.setAttribute('data-tab-no-focus', true);
461
+ tab.id = '';
462
+
463
+ // Change the hash
464
+ location.hash = hash;
465
+
466
+ };
467
+
468
+ /**
469
+ * Destroy the current initialization.
470
+ * @public
471
+ */
472
+ tabby.destroy = function () {
473
+ if (!settings) return;
474
+ document.documentElement.classList.remove(settings.initClass);
475
+ document.removeEventListener('click', clickHandler, false);
476
+ document.removeEventListener('focus', focusHandler, true);
477
+ root.removeEventListener('hashchange', hashChangeHandler, false);
478
+ settings = null;
479
+ tab = null;
480
+ };
481
+
482
+ /**
483
+ * Initialize Tabby
484
+ * @public
485
+ * @param {Object} options User settings
486
+ */
487
+ tabby.init = function (options) {
488
+
489
+ // feature test
490
+ if (!supports) return;
491
+
492
+ // Destroy any existing initializations
493
+ tabby.destroy();
494
+
495
+ // Merge user options with defaults
496
+ settings = extend(defaults, options || {});
497
+
498
+ // Add class to HTML element to activate conditional CSS
499
+ document.documentElement.classList.add(settings.initClass);
500
+
501
+ // Listen for all click events
502
+ document.addEventListener('click', clickHandler, false);
503
+ document.addEventListener('focus', focusHandler, true);
504
+ root.addEventListener('hashchange', hashChangeHandler, false);
505
+
506
+ // If URL has a hash, activate hashed tab by default
507
+ hashChangeHandler();
508
+
509
+ };
510
+
511
+
512
+ //
513
+ // Public APIs
514
+ //
515
+
516
+ return tabby;
517
+
518
+ }));