@flourish/ui-styles 6.0.2 → 7.0.1
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/RELEASE_NOTES.md +6 -0
- package/package.json +4 -3
- package/searchbox-style/settings.yml +82 -0
- package/src/index.js +10 -0
- package/src/searchbox-style/index.js +256 -0
- package/ui-styles.js +1356 -14
- package/ui-styles.min.js +1 -1
package/RELEASE_NOTES.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flourish/ui-styles",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Flourish module for styling UI elements",
|
|
6
6
|
"main": "ui-styles.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"license": "LicenseRef-LICENSE",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"d3-selection": "^1.4.0",
|
|
12
|
-
"@flourish/
|
|
12
|
+
"@flourish/utils-color": "^2.0.0",
|
|
13
|
+
"@flourish/pocket-knife": "^2.3.2"
|
|
13
14
|
},
|
|
14
15
|
"devDependencies": {
|
|
15
16
|
"@babel/core": "^7.23.6",
|
|
@@ -18,10 +19,10 @@
|
|
|
18
19
|
"@rollup/plugin-babel": "^6.0.4",
|
|
19
20
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
20
21
|
"eslint": "^8.35.0",
|
|
22
|
+
"mocha": "^10.2.0",
|
|
21
23
|
"only-allow": "^1.2.1",
|
|
22
24
|
"rollup": "^4.6.1",
|
|
23
25
|
"uglify-js": "^3.17.4",
|
|
24
|
-
"mocha": "^10.2.0",
|
|
25
26
|
"@flourish/mocha-env": "^1.0.0"
|
|
26
27
|
},
|
|
27
28
|
"exports": "./src/index.js",
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
- property: searchbox_input_expanded
|
|
2
|
+
name: Always expand searchbox
|
|
3
|
+
type: boolean
|
|
4
|
+
width: full
|
|
5
|
+
description: If enabled, the search input will be expanded
|
|
6
|
+
|
|
7
|
+
- property: searchbox_styles_display
|
|
8
|
+
name: Customize searchbox styles
|
|
9
|
+
type: boolean
|
|
10
|
+
width: full
|
|
11
|
+
|
|
12
|
+
- property: searchbox_size
|
|
13
|
+
show_if:
|
|
14
|
+
searchbox_styles_display: true
|
|
15
|
+
name: Height
|
|
16
|
+
type: number
|
|
17
|
+
min: 0
|
|
18
|
+
max: 5
|
|
19
|
+
step: 0.1
|
|
20
|
+
width: half
|
|
21
|
+
description: Width and height of the search icon (in rem units)
|
|
22
|
+
|
|
23
|
+
- property: searchbox_width
|
|
24
|
+
show_if:
|
|
25
|
+
searchbox_styles_display: true
|
|
26
|
+
name: Width
|
|
27
|
+
type: number
|
|
28
|
+
min: 1
|
|
29
|
+
step: 1
|
|
30
|
+
width: half
|
|
31
|
+
description: Width of the search input when expanded (in rem units)
|
|
32
|
+
|
|
33
|
+
- property: search_bg_color
|
|
34
|
+
show_if:
|
|
35
|
+
searchbox_styles_display: true
|
|
36
|
+
name: Background
|
|
37
|
+
type: color
|
|
38
|
+
width: half
|
|
39
|
+
optional: true
|
|
40
|
+
description: Background color of the search input and dropdown
|
|
41
|
+
|
|
42
|
+
- property: search_bg_opacity
|
|
43
|
+
show_if:
|
|
44
|
+
searchbox_styles_display: true
|
|
45
|
+
name: Background opacity
|
|
46
|
+
type: number
|
|
47
|
+
step: 0.1
|
|
48
|
+
min: 0
|
|
49
|
+
max: 1
|
|
50
|
+
width: half
|
|
51
|
+
description: A number from 0 to 1 representing the background opacity of the search input and dropdown
|
|
52
|
+
|
|
53
|
+
- property: searchbox_stroke
|
|
54
|
+
show_if:
|
|
55
|
+
searchbox_styles_display: true
|
|
56
|
+
name: Stroke opacity
|
|
57
|
+
type: number
|
|
58
|
+
step: 0.1
|
|
59
|
+
min: 0
|
|
60
|
+
max: 1
|
|
61
|
+
width: half
|
|
62
|
+
description: A number from 0 to 1 representing the opacity of the searchbox stroke
|
|
63
|
+
|
|
64
|
+
- property: searchbox_color
|
|
65
|
+
show_if:
|
|
66
|
+
searchbox_styles_display: true
|
|
67
|
+
name: Color
|
|
68
|
+
type: color
|
|
69
|
+
width: half
|
|
70
|
+
optional: true
|
|
71
|
+
description: Color of the search icon, searchbox stroke, placeholder text and dropdown text
|
|
72
|
+
|
|
73
|
+
- property: searchbox_radius
|
|
74
|
+
show_if:
|
|
75
|
+
searchbox_styles_display: true
|
|
76
|
+
name: Roundness
|
|
77
|
+
type: number
|
|
78
|
+
step: 1
|
|
79
|
+
min: 0
|
|
80
|
+
max: 50
|
|
81
|
+
width: quarter
|
|
82
|
+
description: Roundness of the searchbox (in px)
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,11 @@ import GeneralControlsStyle from "./general-controls-style/index.js";
|
|
|
2
2
|
import ButtonStyle from "./button-style/index.js";
|
|
3
3
|
import DropdownStyle from "./dropdown-style/index.js";
|
|
4
4
|
import SliderStyle from "./slider-style/index.js";
|
|
5
|
+
import SearchboxStyle from "./searchbox-style/index.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('./searchbox-style/index.js').SearchboxStyleState} SearchboxStyleState
|
|
9
|
+
*/
|
|
5
10
|
|
|
6
11
|
function createGeneralControlsStyle(state, selector, layout) {
|
|
7
12
|
return new GeneralControlsStyle(state, selector, layout);
|
|
@@ -19,9 +24,14 @@ function createSliderStyle(state, selector, layout) {
|
|
|
19
24
|
return new SliderStyle(state, selector, layout);
|
|
20
25
|
}
|
|
21
26
|
|
|
27
|
+
function createSearchboxStyle(state, selector, layout) {
|
|
28
|
+
return new SearchboxStyle(state, selector, layout);
|
|
29
|
+
}
|
|
30
|
+
|
|
22
31
|
export {
|
|
23
32
|
createGeneralControlsStyle,
|
|
24
33
|
createButtonStyle,
|
|
25
34
|
createDropdownStyle,
|
|
26
35
|
createSliderStyle,
|
|
36
|
+
createSearchboxStyle,
|
|
27
37
|
};
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { select } from "d3-selection";
|
|
2
|
+
import { isPaleBackground } from "@flourish/utils-color";
|
|
3
|
+
import { hexToRgba } from "@flourish/pocket-knife";
|
|
4
|
+
import Stylesheet from "../lib/js2css.js";
|
|
5
|
+
|
|
6
|
+
const DEFAULTS = Object.freeze({
|
|
7
|
+
searchbox_input_expanded: false,
|
|
8
|
+
searchbox_size: 2,
|
|
9
|
+
searchbox_width: 12,
|
|
10
|
+
search_bg_color: null,
|
|
11
|
+
search_bg_opacity: 0.9,
|
|
12
|
+
searchbox_stroke: 0.1,
|
|
13
|
+
searchbox_color: null,
|
|
14
|
+
searchbox_radius: 4,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
function SearchboxStyle(state_, selector_, layout_) {
|
|
18
|
+
this._state = state_;
|
|
19
|
+
for (const key in DEFAULTS) {
|
|
20
|
+
if (this._state[key] === undefined) this._state[key] = DEFAULTS[key];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this._layout = layout_ || {};
|
|
24
|
+
|
|
25
|
+
this._styles = new Stylesheet();
|
|
26
|
+
this._selector = selector_;
|
|
27
|
+
this._createStylesheet();
|
|
28
|
+
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
SearchboxStyle.prototype._createStylesheet = function () {
|
|
33
|
+
this._stylesheet = document.createElement("style");
|
|
34
|
+
this._stylesheet.className = "fl-ui-styles-searchbox";
|
|
35
|
+
document.head.appendChild(this._stylesheet);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
SearchboxStyle.prototype.update = function () {
|
|
39
|
+
this._styles.clear();
|
|
40
|
+
const prefers_reduced_motion =
|
|
41
|
+
window.matchMedia &&
|
|
42
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
43
|
+
|
|
44
|
+
const bg_color = this._state.search_bg_color || this._layout.background_color;
|
|
45
|
+
const background_color = bg_color
|
|
46
|
+
? hexToRgba(bg_color, this._state.search_bg_opacity)
|
|
47
|
+
: "transparent";
|
|
48
|
+
|
|
49
|
+
const user_defined_searchbox_color =
|
|
50
|
+
this._state.searchbox_color || this._layout.font_color;
|
|
51
|
+
const searchbox_color = user_defined_searchbox_color || "inherit";
|
|
52
|
+
const searchbox_color_paler = user_defined_searchbox_color
|
|
53
|
+
? hexToRgba(
|
|
54
|
+
user_defined_searchbox_color,
|
|
55
|
+
(this._state.searchbox_stroke + 1) / 2,
|
|
56
|
+
)
|
|
57
|
+
: "currentColor";
|
|
58
|
+
const searchbox_color_palest = user_defined_searchbox_color
|
|
59
|
+
? hexToRgba(user_defined_searchbox_color, this._state.searchbox_stroke)
|
|
60
|
+
: "currentColor";
|
|
61
|
+
|
|
62
|
+
const TEXT_SIZE = 0.55; // Relative to the search box height
|
|
63
|
+
const ICON_SIZE = 0.45; // Relative to the search box height
|
|
64
|
+
|
|
65
|
+
// Main container
|
|
66
|
+
this._styles
|
|
67
|
+
.select(this._selector)
|
|
68
|
+
.style("display", "inline-block")
|
|
69
|
+
.style(
|
|
70
|
+
"width",
|
|
71
|
+
this._state.searchbox_size + this._state.searchbox_width + "rem",
|
|
72
|
+
)
|
|
73
|
+
.style("max-width", "calc(100% - 2px)")
|
|
74
|
+
.style("box-sizing", "border-box");
|
|
75
|
+
|
|
76
|
+
select(this._selector).attr(
|
|
77
|
+
"data-pale-background",
|
|
78
|
+
isPaleBackground(background_color),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// Input field
|
|
82
|
+
this._styles
|
|
83
|
+
.select(this._selector + " input")
|
|
84
|
+
.style("border", "2px solid " + searchbox_color_palest)
|
|
85
|
+
.style("border-radius", this._state.searchbox_radius + "px")
|
|
86
|
+
.style("background-color", background_color)
|
|
87
|
+
.style("color", searchbox_color)
|
|
88
|
+
.style("font-family", "inherit")
|
|
89
|
+
.style("cursor", this._state.searchbox_input_expanded ? "text" : "pointer")
|
|
90
|
+
.style("position", "relative")
|
|
91
|
+
.style("opacity", this._state.search_bg_opacity)
|
|
92
|
+
.style("transition", prefers_reduced_motion ? "none" : "200ms width")
|
|
93
|
+
.style("display", "block")
|
|
94
|
+
.style("box-sizing", "border-box")
|
|
95
|
+
.style("padding", "0 0 0 calc(" + this._state.searchbox_size + "rem - 4px)")
|
|
96
|
+
.style("font-size", this._state.searchbox_size * TEXT_SIZE + "rem");
|
|
97
|
+
|
|
98
|
+
this._styles
|
|
99
|
+
.select(this._selector + ".expanded input")
|
|
100
|
+
.style("cursor", "text");
|
|
101
|
+
|
|
102
|
+
if (this._state.searchbox_input_expanded) {
|
|
103
|
+
this._styles
|
|
104
|
+
.select(this._selector + " input")
|
|
105
|
+
.style("width", "100%")
|
|
106
|
+
.style("height", this._state.searchbox_size + "rem");
|
|
107
|
+
} else {
|
|
108
|
+
this._styles
|
|
109
|
+
.select(this._selector + " input")
|
|
110
|
+
.style("width", this._state.searchbox_size + "rem")
|
|
111
|
+
.style("height", this._state.searchbox_size + "rem");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Search icon
|
|
115
|
+
this._styles
|
|
116
|
+
.select(this._selector + " .search-icon")
|
|
117
|
+
.style("position", "absolute")
|
|
118
|
+
.style("pointer-events", "none")
|
|
119
|
+
.style("width", this._state.searchbox_size * ICON_SIZE + "rem")
|
|
120
|
+
.style("height", this._state.searchbox_size * ICON_SIZE + "rem")
|
|
121
|
+
.style(
|
|
122
|
+
"left",
|
|
123
|
+
this._state.searchbox_size * Math.pow(1 - ICON_SIZE, 2) + "rem",
|
|
124
|
+
)
|
|
125
|
+
.style(
|
|
126
|
+
"top",
|
|
127
|
+
this._state.searchbox_size * Math.pow(1 - ICON_SIZE, 2) + "rem",
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// Search icon SVG
|
|
131
|
+
this._styles
|
|
132
|
+
.select(this._selector + " .search-icon svg")
|
|
133
|
+
.style("width", "100%")
|
|
134
|
+
.style("height", "100%")
|
|
135
|
+
.select("path")
|
|
136
|
+
.style("fill", searchbox_color);
|
|
137
|
+
|
|
138
|
+
// Search list (dropdown)
|
|
139
|
+
const list_bg_color =
|
|
140
|
+
this._state.search_bg_color || this._layout.background_color;
|
|
141
|
+
this._styles
|
|
142
|
+
.select(this._selector + " .search-list")
|
|
143
|
+
.style("display", "none")
|
|
144
|
+
.style("opacity", "0")
|
|
145
|
+
.style("margin-top", "1px")
|
|
146
|
+
.style("min-width", "100%")
|
|
147
|
+
.style("max-height", "50vh")
|
|
148
|
+
.style("overflow", "auto")
|
|
149
|
+
.style("position", "absolute")
|
|
150
|
+
.style("box-shadow", "0 1px 3px rgba(0,0,0,0.2)")
|
|
151
|
+
.style("color", searchbox_color)
|
|
152
|
+
.style("border-radius", "3px")
|
|
153
|
+
.style("font-size", this._state.searchbox_size * TEXT_SIZE + "rem")
|
|
154
|
+
.style("z-index", "1000");
|
|
155
|
+
|
|
156
|
+
this._styles
|
|
157
|
+
.select(this._selector + " .search-list.visible")
|
|
158
|
+
.style("opacity", 1)
|
|
159
|
+
.style("visibility", "visible")
|
|
160
|
+
.style("pointer-events", "auto");
|
|
161
|
+
|
|
162
|
+
// Apply data-pale-background to the search-list for accessibility styles
|
|
163
|
+
select(this._selector + " .search-list").attr(
|
|
164
|
+
"data-pale-background",
|
|
165
|
+
isPaleBackground(list_bg_color || background_color),
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// Search list items
|
|
169
|
+
this._styles
|
|
170
|
+
.select(this._selector + " .search-list .search-item")
|
|
171
|
+
.style("height", this._state.searchbox_size * TEXT_SIZE + 1 + "rem")
|
|
172
|
+
.style("background-color", list_bg_color || "transparent")
|
|
173
|
+
.style("opacity", this._state.search_bg_opacity)
|
|
174
|
+
.style("padding", "0.5rem")
|
|
175
|
+
.style("cursor", "pointer")
|
|
176
|
+
.style("position", "relative")
|
|
177
|
+
.select("p")
|
|
178
|
+
.style("margin", "0")
|
|
179
|
+
.style("line-height", "1.2em")
|
|
180
|
+
.style("display", "block")
|
|
181
|
+
.style("white-space", "nowrap")
|
|
182
|
+
.style("font-weight", "normal")
|
|
183
|
+
.style("overflow", "hidden")
|
|
184
|
+
.style("text-overflow", "ellipsis")
|
|
185
|
+
.style("pointer-events", "none");
|
|
186
|
+
|
|
187
|
+
// Search list item hover and selected states for pale backgrounds
|
|
188
|
+
this._styles
|
|
189
|
+
.select(
|
|
190
|
+
this._selector +
|
|
191
|
+
" .search-list[data-pale-background='true'] .search-item:hover",
|
|
192
|
+
)
|
|
193
|
+
.style("outline", "2px solid black")
|
|
194
|
+
.style("outline-offset", "-2px");
|
|
195
|
+
|
|
196
|
+
this._styles
|
|
197
|
+
.select(
|
|
198
|
+
this._selector +
|
|
199
|
+
" .search-list[data-pale-background='true'] .search-item.selected",
|
|
200
|
+
)
|
|
201
|
+
.style("outline", "2px solid black")
|
|
202
|
+
.style("outline-offset", "-2px")
|
|
203
|
+
.style("cursor", "default");
|
|
204
|
+
|
|
205
|
+
this._styles
|
|
206
|
+
.select(
|
|
207
|
+
this._selector +
|
|
208
|
+
" .search-list[data-pale-background='true'] .search-item:focus-visible",
|
|
209
|
+
)
|
|
210
|
+
.style("outline", "2px solid black")
|
|
211
|
+
.style("outline-offset", "-2px");
|
|
212
|
+
|
|
213
|
+
// Search list item hover and selected states for dark backgrounds
|
|
214
|
+
this._styles
|
|
215
|
+
.select(
|
|
216
|
+
this._selector +
|
|
217
|
+
" .search-list[data-pale-background='false'] .search-item:hover",
|
|
218
|
+
)
|
|
219
|
+
.style("outline", "2px solid white")
|
|
220
|
+
.style("outline-offset", "-2px");
|
|
221
|
+
|
|
222
|
+
this._styles
|
|
223
|
+
.select(
|
|
224
|
+
this._selector +
|
|
225
|
+
" .search-list[data-pale-background='false'] .search-item.selected",
|
|
226
|
+
)
|
|
227
|
+
.style("outline", "2px solid white")
|
|
228
|
+
.style("outline-offset", "-2px")
|
|
229
|
+
.style("cursor", "default");
|
|
230
|
+
|
|
231
|
+
this._styles
|
|
232
|
+
.select(
|
|
233
|
+
this._selector +
|
|
234
|
+
" .search-list[data-pale-background='false'] .search-item:focus-visible",
|
|
235
|
+
)
|
|
236
|
+
.style("outline", "2px solid white")
|
|
237
|
+
.style("outline-offset", "-2px");
|
|
238
|
+
|
|
239
|
+
// Active state (when search is focused)
|
|
240
|
+
this._styles
|
|
241
|
+
.select(this._selector + ".active .search-list")
|
|
242
|
+
.style("display", "block");
|
|
243
|
+
|
|
244
|
+
// Expanded state
|
|
245
|
+
this._styles
|
|
246
|
+
.select(this._selector + ".expanded input")
|
|
247
|
+
.style("width", "100% !important");
|
|
248
|
+
|
|
249
|
+
this._styles
|
|
250
|
+
.select(this._selector + " input::placeholder")
|
|
251
|
+
.style("color", searchbox_color_paler);
|
|
252
|
+
|
|
253
|
+
this._stylesheet.innerHTML = this._styles.print();
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
export default SearchboxStyle;
|