vanilla-framework 4.34.1 → 4.34.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.
- package/package.json +11 -2
- package/scss/_layouts_application.scss +3 -3
- package/scss/_layouts_docs.scss +1 -1
- package/scss/_layouts_full-width.scss +1 -1
- package/scss/_layouts_site.scss +1 -1
- package/scss/_patterns_navigation.scss +5 -4
- package/scss/_patterns_side-navigation.scss +1 -1
- package/templates/static/js/example-tools.js +181 -0
- package/templates/static/js/example.js +554 -0
- package/templates/static/js/index.js +16 -0
- package/templates/static/js/package.json +3 -0
- package/templates/static/js/prism.min.js +8 -0
- package/templates/static/js/scripts.js +418 -0
- package/templates/static/js/tabs.js +111 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanilla-framework",
|
|
3
|
-
"version": "4.34.
|
|
3
|
+
"version": "4.34.2",
|
|
4
4
|
"author": {
|
|
5
5
|
"email": "webteam@canonical.com",
|
|
6
6
|
"name": "Canonical Webteam"
|
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
"module"
|
|
23
23
|
],
|
|
24
24
|
"license": "LGPL-3.0",
|
|
25
|
+
"module": "templates/static/js/index.js",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"sass": "./_index.scss"
|
|
29
|
+
},
|
|
30
|
+
"./js": "./templates/static/js/index.js",
|
|
31
|
+
"./js/*": "./templates/static/js/*.js"
|
|
32
|
+
},
|
|
25
33
|
"repository": {
|
|
26
34
|
"type": "git",
|
|
27
35
|
"url": "https://github.com/canonical/vanilla-framework"
|
|
@@ -54,7 +62,8 @@
|
|
|
54
62
|
"/scss",
|
|
55
63
|
"!/scss/docs",
|
|
56
64
|
"!/scss/standalone",
|
|
57
|
-
"/templates/_macros"
|
|
65
|
+
"/templates/_macros",
|
|
66
|
+
"/templates/static/js"
|
|
58
67
|
],
|
|
59
68
|
"devDependencies": {
|
|
60
69
|
"@canonical/cookie-policy": "3.6.5",
|
|
@@ -52,7 +52,7 @@ $application-layout--side-nav-width-expanded: 15rem !default;
|
|
|
52
52
|
'nav status status';
|
|
53
53
|
grid-template-columns: min-content minmax(0, 1fr) minmax(0, min-content);
|
|
54
54
|
grid-template-rows: min-content 1fr min-content;
|
|
55
|
-
height:
|
|
55
|
+
height: 100dvh;
|
|
56
56
|
overflow: hidden; // make sure panels transformed off-screen don't make the layout scroll
|
|
57
57
|
width: 100vw;
|
|
58
58
|
}
|
|
@@ -69,7 +69,7 @@ $application-layout--side-nav-width-expanded: 15rem !default;
|
|
|
69
69
|
|
|
70
70
|
bottom: 0;
|
|
71
71
|
box-shadow: $panel-drop-shadow;
|
|
72
|
-
height:
|
|
72
|
+
height: 100dvh;
|
|
73
73
|
left: 0;
|
|
74
74
|
overflow-y: auto;
|
|
75
75
|
position: fixed;
|
|
@@ -94,7 +94,7 @@ $application-layout--side-nav-width-expanded: 15rem !default;
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
.l-navigation__drawer {
|
|
97
|
-
height:
|
|
97
|
+
height: 100dvh;
|
|
98
98
|
width: auto;
|
|
99
99
|
|
|
100
100
|
@media (min-width: $breakpoint-x-small) {
|
package/scss/_layouts_docs.scss
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
$navigation-top-height: $spv--large * 2 + map-get($settings-text-default, line-height);
|
|
26
26
|
|
|
27
27
|
height: calc(100% - $navigation-top-height); // height of document reduced by height of top nav
|
|
28
|
-
min-height: calc(
|
|
28
|
+
min-height: calc(100dvh - $navigation-top-height);
|
|
29
29
|
position: absolute;
|
|
30
30
|
width: $l-full-screen-aside-width;
|
|
31
31
|
z-index: 1;
|
package/scss/_layouts_site.scss
CHANGED
|
@@ -843,8 +843,8 @@ $navigation-height: calc(map-get($settings-text-p, line-height) + 2 * $spv--larg
|
|
|
843
843
|
|
|
844
844
|
.p-navigation--sliding.has-menu-open,
|
|
845
845
|
.p-navigation--reduced.has-menu-open {
|
|
846
|
-
box-shadow: $colors--theme--background-overlay 0px 0px 0px
|
|
847
|
-
height:
|
|
846
|
+
box-shadow: $colors--theme--background-overlay 0px 0px 0px 100dvh;
|
|
847
|
+
height: 100dvh;
|
|
848
848
|
overflow-y: hidden;
|
|
849
849
|
position: fixed;
|
|
850
850
|
width: 100vw;
|
|
@@ -866,7 +866,7 @@ $navigation-height: calc(map-get($settings-text-p, line-height) + 2 * $spv--larg
|
|
|
866
866
|
}
|
|
867
867
|
.p-navigation__nav {
|
|
868
868
|
display: block;
|
|
869
|
-
height: calc(
|
|
869
|
+
height: calc(100dvh - $navigation-height);
|
|
870
870
|
overflow-x: hidden;
|
|
871
871
|
|
|
872
872
|
.p-navigation__items {
|
|
@@ -893,7 +893,7 @@ $navigation-height: calc(map-get($settings-text-p, line-height) + 2 * $spv--larg
|
|
|
893
893
|
.p-navigation--sliding .p-navigation__dropdown,
|
|
894
894
|
.p-navigation--reduced .p-navigation__dropdown {
|
|
895
895
|
display: block;
|
|
896
|
-
height: calc(
|
|
896
|
+
height: calc(100dvh - $navigation-height);
|
|
897
897
|
left: 100vw;
|
|
898
898
|
position: absolute;
|
|
899
899
|
top: 0;
|
|
@@ -1007,6 +1007,7 @@ $navigation-height: calc(map-get($settings-text-p, line-height) + 2 * $spv--larg
|
|
|
1007
1007
|
.p-navigation__dropdown > :last-child {
|
|
1008
1008
|
// should be enough to make some space at the bottom
|
|
1009
1009
|
// and workaround the issues of 100vh not taking address toolbar into account
|
|
1010
|
+
// this workaround might not be needed since we moved from 100vh to 100dvh
|
|
1010
1011
|
padding-bottom: 3rem;
|
|
1011
1012
|
|
|
1012
1013
|
@media (min-width: $breakpoint-navigation-threshold) {
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
const SUPPORTED_THEMES = ['light', 'dark', 'paper'];
|
|
2
|
+
const [DEFAULT_COLOR_THEME] = SUPPORTED_THEMES;
|
|
3
|
+
const COLOR_THEME_QUERY_PARAM_NAME = 'theme';
|
|
4
|
+
var activeTheme = DEFAULT_COLOR_THEME;
|
|
5
|
+
|
|
6
|
+
(function () {
|
|
7
|
+
function inIframe() {
|
|
8
|
+
try {
|
|
9
|
+
return window.self !== window.top;
|
|
10
|
+
} catch (e) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function fragmentFromString(htmlString) {
|
|
16
|
+
var temp = document.createElement('template');
|
|
17
|
+
temp.innerHTML = htmlString;
|
|
18
|
+
return temp.content;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Gets the current query parameters
|
|
23
|
+
* @returns {URLSearchParams}
|
|
24
|
+
*/
|
|
25
|
+
function getQueryParameters() {
|
|
26
|
+
return new URLSearchParams(window.location.search);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Sets the query parameter value of `key` to `value`
|
|
31
|
+
* @param {String} key
|
|
32
|
+
* @param {String} value
|
|
33
|
+
* @param {Boolean} reload Whether to cause a page load after updating the query parameter
|
|
34
|
+
* @returns {URLSearchParams} Query parameters after update
|
|
35
|
+
*/
|
|
36
|
+
function setQueryParameter(key, value, reload = false) {
|
|
37
|
+
var currentQueryParams = getQueryParameters();
|
|
38
|
+
|
|
39
|
+
if (reload && currentQueryParams.get(key) !== value) {
|
|
40
|
+
currentQueryParams.set(key, value);
|
|
41
|
+
window.location.search = currentQueryParams.toString();
|
|
42
|
+
} else {
|
|
43
|
+
var url = new URL(window.location.href);
|
|
44
|
+
if (value) {
|
|
45
|
+
url.searchParams.set(key, value);
|
|
46
|
+
} else {
|
|
47
|
+
url.searchParams.delete(key);
|
|
48
|
+
}
|
|
49
|
+
if (window.location.href !== url.toString()) {
|
|
50
|
+
window.history.replaceState(null, null, url.toString());
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return getQueryParameters();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Converts a theme name to its document class name, used for applying that color theme to the body
|
|
58
|
+
* @param {String} themeName
|
|
59
|
+
* @returns {string}
|
|
60
|
+
*/
|
|
61
|
+
function convertThemeNameToClassName(themeName) {
|
|
62
|
+
return `is-${themeName}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Converts a theme name to its JS toggler identifier name, used for targeting it with JS events
|
|
67
|
+
* @param {String} themeName
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
function convertThemeNameToButtonIdentifier(themeName) {
|
|
71
|
+
return `js-${themeName}-theme-toggle`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Converts a string to titlecase (first letter capitalized & subsequent letters lowercase)
|
|
76
|
+
* @param {String} str
|
|
77
|
+
* @returns {string}
|
|
78
|
+
*/
|
|
79
|
+
function titleCase(str) {
|
|
80
|
+
return `${str.charAt(0).toUpperCase()}${str.slice(1).toLowerCase()}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Sets a color theme as active; removes all other color themes from active status
|
|
85
|
+
* @param {String} themeToSelect
|
|
86
|
+
*/
|
|
87
|
+
function selectColorTheme(themeToSelect) {
|
|
88
|
+
// Apply the color theme to the document body
|
|
89
|
+
document.body.classList.add(convertThemeNameToClassName(themeToSelect));
|
|
90
|
+
// Remove the old color theme from the document body
|
|
91
|
+
if (themeToSelect !== activeTheme) document.body.classList.remove(convertThemeNameToClassName(activeTheme));
|
|
92
|
+
|
|
93
|
+
// Update address bar to reflect the newly selected color theme
|
|
94
|
+
setQueryParameter(COLOR_THEME_QUERY_PARAM_NAME, themeToSelect.toLowerCase());
|
|
95
|
+
|
|
96
|
+
// Update theme selector button states to reflect which one is currently active
|
|
97
|
+
var themeButtonToSelect = document.getElementById(convertThemeNameToButtonIdentifier(themeToSelect));
|
|
98
|
+
themeButtonToSelect?.setAttribute('aria-selected', 'true');
|
|
99
|
+
if (activeTheme) {
|
|
100
|
+
var themeButtonToDeselect = document.getElementById(convertThemeNameToButtonIdentifier(activeTheme));
|
|
101
|
+
themeButtonToDeselect?.setAttribute('aria-selected', 'false');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
activeTheme = themeToSelect;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!inIframe()) {
|
|
108
|
+
document.documentElement.classList.add('u-baseline-grid');
|
|
109
|
+
|
|
110
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
111
|
+
var body = document.body;
|
|
112
|
+
var controls = document.createElement('div');
|
|
113
|
+
controls.classList.add('p-example-controls', 'p-form');
|
|
114
|
+
var queryParameters = getQueryParameters();
|
|
115
|
+
var requestedTheme = queryParameters.get(COLOR_THEME_QUERY_PARAM_NAME);
|
|
116
|
+
if (SHOW_THEME_SWITCH) {
|
|
117
|
+
// Some examples (i.e., button / dark) are pre-themed by their jinja template.
|
|
118
|
+
// if this is the case we don't modify the body class (it's already set); we just mark that theme as active.
|
|
119
|
+
var preExistingClassFromTemplate = SUPPORTED_THEMES.find((themeName) => body.classList.contains(convertThemeNameToClassName(themeName)));
|
|
120
|
+
|
|
121
|
+
if (preExistingClassFromTemplate) {
|
|
122
|
+
activeTheme = preExistingClassFromTemplate;
|
|
123
|
+
} else if (!requestedTheme) {
|
|
124
|
+
// No template-defined theme & no query-param-requested theme; fallback to default
|
|
125
|
+
selectColorTheme(DEFAULT_COLOR_THEME);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (requestedTheme) {
|
|
129
|
+
if (SUPPORTED_THEMES.includes(requestedTheme)) {
|
|
130
|
+
selectColorTheme(requestedTheme);
|
|
131
|
+
} else {
|
|
132
|
+
// Query param used to request a theme that is not supported
|
|
133
|
+
selectColorTheme(DEFAULT_COLOR_THEME);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (SUPPORTED_THEMES?.length > 1) {
|
|
138
|
+
var themeSwitcherControls = SUPPORTED_THEMES.map(
|
|
139
|
+
(themeName) =>
|
|
140
|
+
`<button id="${convertThemeNameToButtonIdentifier(themeName)}" class="p-segmented-control__button p-theme-toggle__button is-dense" role="button" aria-selected="${body.classList.contains(convertThemeNameToClassName(themeName))}" data-color-theme-name="${themeName}">${titleCase(themeName)}</button>`,
|
|
141
|
+
);
|
|
142
|
+
var themeSwitcherSegmentedControl = fragmentFromString(
|
|
143
|
+
`<div class="p-segmented-control u-theme-toggle"><div class="p-segmented-control__list">${themeSwitcherControls.join('')}</div></div>`,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
controls.appendChild(themeSwitcherSegmentedControl);
|
|
147
|
+
}
|
|
148
|
+
} else if (requestedTheme) {
|
|
149
|
+
setQueryParameter(COLOR_THEME_QUERY_PARAM_NAME, null);
|
|
150
|
+
}
|
|
151
|
+
var baselineGridControl = fragmentFromString(
|
|
152
|
+
'<div class="u-baseline-grid__toggle"><label class="p-switch"><input type="checkbox" class="p-switch__input js-baseline-toggle" /><span class="p-switch__slider"></span><span class="p-switch__label">Toggle baseline grid</span></label></div>',
|
|
153
|
+
);
|
|
154
|
+
controls.appendChild(baselineGridControl);
|
|
155
|
+
|
|
156
|
+
const closeButtonFragment = fragmentFromString(`
|
|
157
|
+
<button class="p-button is-dense p-example-controls__close-button" id="js-example-toolbar-close-button">
|
|
158
|
+
Close
|
|
159
|
+
</button>
|
|
160
|
+
`);
|
|
161
|
+
controls.appendChild(closeButtonFragment);
|
|
162
|
+
body.appendChild(controls);
|
|
163
|
+
|
|
164
|
+
var closeButton = document.getElementById('js-example-toolbar-close-button');
|
|
165
|
+
closeButton.addEventListener('click', () => controls.remove());
|
|
166
|
+
|
|
167
|
+
// Below code relies on the controls already existing in the DOM, so must come after `body.appendChild`.
|
|
168
|
+
var themeToggleButtons = document.querySelectorAll('.p-theme-toggle__button');
|
|
169
|
+
themeToggleButtons.forEach((themeToggleButton) => {
|
|
170
|
+
themeToggleButton.addEventListener('click', () => {
|
|
171
|
+
selectColorTheme(themeToggleButton.getAttribute('data-color-theme-name'));
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
var toggle = document.querySelector('.js-baseline-toggle');
|
|
176
|
+
toggle.addEventListener('click', function (event) {
|
|
177
|
+
body.classList.toggle('u-baseline-grid');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
})();
|