baseline-foundry 0.1.3
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/LICENSE +21 -0
- package/README.md +588 -0
- package/config/experiments/ibm-plex-engine-smoke.json +115 -0
- package/config/experiments/ubuntu-engine-smoke.json +115 -0
- package/config/foundation-theme.json +117 -0
- package/config/tiers/app.json +120 -0
- package/config/tiers/documentation.json +120 -0
- package/config/tiers/editorial.json +120 -0
- package/config/tiers/os.json +120 -0
- package/dist/accordion.d.ts +5 -0
- package/dist/accordion.js +32 -0
- package/dist/application-layout.d.ts +4 -0
- package/dist/application-layout.js +181 -0
- package/dist/baseline-grid-overlay.d.ts +5 -0
- package/dist/baseline-grid-overlay.js +50 -0
- package/dist/baseline-grid-theme.d.ts +3 -0
- package/dist/baseline-grid-theme.js +3 -0
- package/dist/baseline-grid.d.ts +7 -0
- package/dist/baseline-grid.js +35 -0
- package/dist/build.d.ts +21 -0
- package/dist/build.js +440 -0
- package/dist/code-snippet.d.ts +6 -0
- package/dist/code-snippet.js +95 -0
- package/dist/contextual-menu.d.ts +4 -0
- package/dist/contextual-menu.js +156 -0
- package/dist/css-app-tier.d.ts +1 -0
- package/dist/css-app-tier.js +77 -0
- package/dist/css-components/article-pagination.d.ts +13 -0
- package/dist/css-components/article-pagination.js +151 -0
- package/dist/css-components/button-actions.d.ts +7 -0
- package/dist/css-components/button-actions.js +165 -0
- package/dist/css-components/cards-options.d.ts +6 -0
- package/dist/css-components/cards-options.js +180 -0
- package/dist/css-components/chip-badge-status.d.ts +10 -0
- package/dist/css-components/chip-badge-status.js +162 -0
- package/dist/css-components/content-card.d.ts +25 -0
- package/dist/css-components/content-card.js +517 -0
- package/dist/css-components/control-row.d.ts +2 -0
- package/dist/css-components/control-row.js +18 -0
- package/dist/css-components/cta-figure-aspect.d.ts +1 -0
- package/dist/css-components/cta-figure-aspect.js +123 -0
- package/dist/css-components/document-navigation.d.ts +13 -0
- package/dist/css-components/document-navigation.js +400 -0
- package/dist/css-components/editorial-content.d.ts +6 -0
- package/dist/css-components/editorial-content.js +52 -0
- package/dist/css-components/icon.d.ts +1 -0
- package/dist/css-components/icon.js +75 -0
- package/dist/css-components/interactive-feedback.d.ts +2 -0
- package/dist/css-components/interactive-feedback.js +230 -0
- package/dist/css-components/interactive-tables.d.ts +7 -0
- package/dist/css-components/interactive-tables.js +164 -0
- package/dist/css-components/linked-logo-site-layout.d.ts +21 -0
- package/dist/css-components/linked-logo-site-layout.js +214 -0
- package/dist/css-components/list-tree.d.ts +5 -0
- package/dist/css-components/list-tree.js +98 -0
- package/dist/css-components/list.d.ts +3 -0
- package/dist/css-components/list.js +119 -0
- package/dist/css-components/logo-media.d.ts +16 -0
- package/dist/css-components/logo-media.js +219 -0
- package/dist/css-components/navigation-layout.d.ts +5 -0
- package/dist/css-components/navigation-layout.js +151 -0
- package/dist/css-components/panel.d.ts +6 -0
- package/dist/css-components/panel.js +148 -0
- package/dist/css-components/search-box-and-filter.d.ts +9 -0
- package/dist/css-components/search-box-and-filter.js +267 -0
- package/dist/css-components/sites-editorial-ports.d.ts +19 -0
- package/dist/css-components/sites-editorial-ports.js +264 -0
- package/dist/css-components/sites-foundation.d.ts +17 -0
- package/dist/css-components/sites-foundation.js +173 -0
- package/dist/css-components/sites-rich-lists.d.ts +18 -0
- package/dist/css-components/sites-rich-lists.js +364 -0
- package/dist/css-components/static-content-ports.d.ts +14 -0
- package/dist/css-components/static-content-ports.js +206 -0
- package/dist/css-components/tab-section.d.ts +19 -0
- package/dist/css-components/tab-section.js +103 -0
- package/dist/css-components/table.d.ts +7 -0
- package/dist/css-components/table.js +79 -0
- package/dist/css-components/tabs-choice-breadcrumbs.d.ts +9 -0
- package/dist/css-components/tabs-choice-breadcrumbs.js +307 -0
- package/dist/css-components/tiered-list-equal-height-row.d.ts +1 -0
- package/dist/css-components/tiered-list-equal-height-row.js +286 -0
- package/dist/css-components.d.ts +2 -0
- package/dist/css-components.js +2701 -0
- package/dist/css-grid.d.ts +1 -0
- package/dist/css-grid.js +179 -0
- package/dist/css.d.ts +6 -0
- package/dist/css.js +431 -0
- package/dist/experiments/ibm-plex-engine-smoke/styles.css +8969 -0
- package/dist/experiments/ibm-plex-engine-smoke/surfaces.json +604 -0
- package/dist/experiments/ibm-plex-engine-smoke/tokens.json +217 -0
- package/dist/in-page-navigation.d.ts +7 -0
- package/dist/in-page-navigation.js +136 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +18 -0
- package/dist/interactive-feedback.d.ts +14 -0
- package/dist/interactive-feedback.js +96 -0
- package/dist/interactive-tables.d.ts +28 -0
- package/dist/interactive-tables.js +184 -0
- package/dist/list-tree.d.ts +4 -0
- package/dist/list-tree.js +44 -0
- package/dist/panel-drawer.d.ts +4 -0
- package/dist/panel-drawer.js +171 -0
- package/dist/presets/app-tier/styles.css +9459 -0
- package/dist/presets/app-tier/surfaces.json +1225 -0
- package/dist/presets/app-tier/tokens.json +221 -0
- package/dist/presets/prose/styles.css +9442 -0
- package/dist/presets/prose/surfaces.json +1225 -0
- package/dist/presets/prose/tokens.json +221 -0
- package/dist/presets.d.ts +6 -0
- package/dist/presets.js +27 -0
- package/dist/range-controls.d.ts +9 -0
- package/dist/range-controls.js +73 -0
- package/dist/resizable-aside.d.ts +4 -0
- package/dist/resizable-aside.js +328 -0
- package/dist/side-navigation.d.ts +4 -0
- package/dist/side-navigation.js +219 -0
- package/dist/styles.css +9442 -0
- package/dist/surfaces.json +1225 -0
- package/dist/tabs.d.ts +4 -0
- package/dist/tabs.js +88 -0
- package/dist/tier-registry.d.ts +10 -0
- package/dist/tier-registry.js +25 -0
- package/dist/tiers/app/styles.css +9459 -0
- package/dist/tiers/app/surfaces.json +1225 -0
- package/dist/tiers/app/tokens.json +221 -0
- package/dist/tiers/documentation/styles.css +9442 -0
- package/dist/tiers/documentation/surfaces.json +1225 -0
- package/dist/tiers/documentation/tokens.json +221 -0
- package/dist/tiers/editorial/styles.css +9442 -0
- package/dist/tiers/editorial/surfaces.json +1225 -0
- package/dist/tiers/editorial/tokens.json +221 -0
- package/dist/tiers/os/styles.css +9442 -0
- package/dist/tiers/os/surfaces.json +1225 -0
- package/dist/tiers/os/tokens.json +221 -0
- package/dist/tokens.json +221 -0
- package/dist/tooltip.d.ts +4 -0
- package/dist/tooltip.js +70 -0
- package/dist/top-navigation.d.ts +4 -0
- package/dist/top-navigation.js +354 -0
- package/dist/types.d.ts +155 -0
- package/dist/types.js +1 -0
- package/dist/vanilla-theme-colors.d.ts +5 -0
- package/dist/vanilla-theme-colors.js +208 -0
- package/docs/publishing.md +66 -0
- package/package.json +108 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
{
|
|
2
|
+
"baselineUnit": "0.5rem",
|
|
3
|
+
"fontFiles": [
|
|
4
|
+
{
|
|
5
|
+
"family": "ubuntu-sans",
|
|
6
|
+
"path": "../../../assets/fonts/UbuntuSans[wdth,wght].ttf",
|
|
7
|
+
"cssFamily": "Ubuntu Sans",
|
|
8
|
+
"fontStyle": "normal",
|
|
9
|
+
"fontWeight": "100 800",
|
|
10
|
+
"fontStretch": "75% 100%",
|
|
11
|
+
"fontDisplay": "swap",
|
|
12
|
+
"emitFontFace": false
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"fontStacks": {
|
|
16
|
+
"ubuntu-sans": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif"
|
|
17
|
+
},
|
|
18
|
+
"roles": {
|
|
19
|
+
"body": {
|
|
20
|
+
"fontSize": "1rem",
|
|
21
|
+
"lineHeight": "1.5rem",
|
|
22
|
+
"fontFamily": "ubuntu-sans",
|
|
23
|
+
"fontWeight": 400,
|
|
24
|
+
"fontStyle": "normal",
|
|
25
|
+
"spaceAfter": "1rem",
|
|
26
|
+
"nudgeTop": "0.41rem",
|
|
27
|
+
"identifier": "body",
|
|
28
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
29
|
+
"marginBottom": "0.09rem"
|
|
30
|
+
},
|
|
31
|
+
"h1": {
|
|
32
|
+
"fontSize": "2.625rem",
|
|
33
|
+
"lineHeight": "3rem",
|
|
34
|
+
"fontFamily": "ubuntu-sans",
|
|
35
|
+
"fontWeight": 500,
|
|
36
|
+
"fontStyle": "normal",
|
|
37
|
+
"spaceAfter": "1rem",
|
|
38
|
+
"nudgeTop": "0.06881rem",
|
|
39
|
+
"identifier": "h1",
|
|
40
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
41
|
+
"marginBottom": "0.43119rem"
|
|
42
|
+
},
|
|
43
|
+
"h2": {
|
|
44
|
+
"fontSize": "2.625rem",
|
|
45
|
+
"lineHeight": "3rem",
|
|
46
|
+
"fontFamily": "ubuntu-sans",
|
|
47
|
+
"fontWeight": 200,
|
|
48
|
+
"fontStyle": "normal",
|
|
49
|
+
"spaceAfter": "1rem",
|
|
50
|
+
"nudgeTop": "0.06881rem",
|
|
51
|
+
"identifier": "h2",
|
|
52
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
53
|
+
"marginBottom": "0.43119rem"
|
|
54
|
+
},
|
|
55
|
+
"h3": {
|
|
56
|
+
"fontSize": "1.5rem",
|
|
57
|
+
"lineHeight": "2rem",
|
|
58
|
+
"fontFamily": "ubuntu-sans",
|
|
59
|
+
"fontWeight": 500,
|
|
60
|
+
"fontStyle": "normal",
|
|
61
|
+
"spaceAfter": "1rem",
|
|
62
|
+
"nudgeTop": "0.46917rem",
|
|
63
|
+
"identifier": "h3",
|
|
64
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
65
|
+
"marginBottom": "0.03083rem"
|
|
66
|
+
},
|
|
67
|
+
"h4": {
|
|
68
|
+
"fontSize": "1.5rem",
|
|
69
|
+
"lineHeight": "2rem",
|
|
70
|
+
"fontFamily": "ubuntu-sans",
|
|
71
|
+
"fontWeight": 300,
|
|
72
|
+
"fontStyle": "normal",
|
|
73
|
+
"spaceAfter": "1rem",
|
|
74
|
+
"nudgeTop": "0.46917rem",
|
|
75
|
+
"identifier": "h4",
|
|
76
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
77
|
+
"marginBottom": "0.03083rem"
|
|
78
|
+
},
|
|
79
|
+
"h5": {
|
|
80
|
+
"fontSize": "1rem",
|
|
81
|
+
"lineHeight": "1.5rem",
|
|
82
|
+
"fontFamily": "ubuntu-sans",
|
|
83
|
+
"fontWeight": 550,
|
|
84
|
+
"fontStyle": "normal",
|
|
85
|
+
"spaceAfter": "1rem",
|
|
86
|
+
"nudgeTop": "0.41rem",
|
|
87
|
+
"identifier": "h5",
|
|
88
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
89
|
+
"marginBottom": "0.09rem",
|
|
90
|
+
"fontVariantCaps": "all-small-caps",
|
|
91
|
+
"letterSpacing": "0.05em"
|
|
92
|
+
},
|
|
93
|
+
"h6": {
|
|
94
|
+
"fontSize": "1rem",
|
|
95
|
+
"lineHeight": "1.5rem",
|
|
96
|
+
"fontFamily": "ubuntu-sans",
|
|
97
|
+
"fontWeight": 550,
|
|
98
|
+
"fontStyle": "normal",
|
|
99
|
+
"spaceAfter": "1rem",
|
|
100
|
+
"nudgeTop": "0.41rem",
|
|
101
|
+
"identifier": "h6",
|
|
102
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
103
|
+
"marginBottom": "0.09rem"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"elements": {
|
|
107
|
+
"body": {
|
|
108
|
+
"fontSize": "1rem",
|
|
109
|
+
"lineHeight": "1.5rem",
|
|
110
|
+
"fontFamily": "ubuntu-sans",
|
|
111
|
+
"fontWeight": 400,
|
|
112
|
+
"fontStyle": "normal",
|
|
113
|
+
"spaceAfter": "1rem",
|
|
114
|
+
"nudgeTop": "0.41rem",
|
|
115
|
+
"identifier": "body",
|
|
116
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
117
|
+
"marginBottom": "0.09rem"
|
|
118
|
+
},
|
|
119
|
+
"h6": {
|
|
120
|
+
"fontSize": "1rem",
|
|
121
|
+
"lineHeight": "1.5rem",
|
|
122
|
+
"fontFamily": "ubuntu-sans",
|
|
123
|
+
"fontWeight": 550,
|
|
124
|
+
"fontStyle": "normal",
|
|
125
|
+
"spaceAfter": "1rem",
|
|
126
|
+
"nudgeTop": "0.41rem",
|
|
127
|
+
"identifier": "h6",
|
|
128
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
129
|
+
"marginBottom": "0.09rem"
|
|
130
|
+
},
|
|
131
|
+
"h5": {
|
|
132
|
+
"fontSize": "1rem",
|
|
133
|
+
"lineHeight": "1.5rem",
|
|
134
|
+
"fontFamily": "ubuntu-sans",
|
|
135
|
+
"fontWeight": 550,
|
|
136
|
+
"fontStyle": "normal",
|
|
137
|
+
"spaceAfter": "1rem",
|
|
138
|
+
"nudgeTop": "0.41rem",
|
|
139
|
+
"identifier": "h5",
|
|
140
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
141
|
+
"marginBottom": "0.09rem",
|
|
142
|
+
"fontVariantCaps": "all-small-caps",
|
|
143
|
+
"letterSpacing": "0.05em"
|
|
144
|
+
},
|
|
145
|
+
"h4": {
|
|
146
|
+
"fontSize": "1.5rem",
|
|
147
|
+
"lineHeight": "2rem",
|
|
148
|
+
"fontFamily": "ubuntu-sans",
|
|
149
|
+
"fontWeight": 300,
|
|
150
|
+
"fontStyle": "normal",
|
|
151
|
+
"spaceAfter": "1rem",
|
|
152
|
+
"nudgeTop": "0.46917rem",
|
|
153
|
+
"identifier": "h4",
|
|
154
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
155
|
+
"marginBottom": "0.03083rem"
|
|
156
|
+
},
|
|
157
|
+
"h3": {
|
|
158
|
+
"fontSize": "1.5rem",
|
|
159
|
+
"lineHeight": "2rem",
|
|
160
|
+
"fontFamily": "ubuntu-sans",
|
|
161
|
+
"fontWeight": 500,
|
|
162
|
+
"fontStyle": "normal",
|
|
163
|
+
"spaceAfter": "1rem",
|
|
164
|
+
"nudgeTop": "0.46917rem",
|
|
165
|
+
"identifier": "h3",
|
|
166
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
167
|
+
"marginBottom": "0.03083rem"
|
|
168
|
+
},
|
|
169
|
+
"h2": {
|
|
170
|
+
"fontSize": "2.625rem",
|
|
171
|
+
"lineHeight": "3rem",
|
|
172
|
+
"fontFamily": "ubuntu-sans",
|
|
173
|
+
"fontWeight": 200,
|
|
174
|
+
"fontStyle": "normal",
|
|
175
|
+
"spaceAfter": "1rem",
|
|
176
|
+
"nudgeTop": "0.06881rem",
|
|
177
|
+
"identifier": "h2",
|
|
178
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
179
|
+
"marginBottom": "0.43119rem"
|
|
180
|
+
},
|
|
181
|
+
"h1": {
|
|
182
|
+
"fontSize": "2.625rem",
|
|
183
|
+
"lineHeight": "3rem",
|
|
184
|
+
"fontFamily": "ubuntu-sans",
|
|
185
|
+
"fontWeight": 500,
|
|
186
|
+
"fontStyle": "normal",
|
|
187
|
+
"spaceAfter": "1rem",
|
|
188
|
+
"nudgeTop": "0.06881rem",
|
|
189
|
+
"identifier": "h1",
|
|
190
|
+
"fontStack": "\"Ubuntu Sans\", \"Segoe UI\", system-ui, sans-serif",
|
|
191
|
+
"marginBottom": "0.43119rem"
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
"layout": {
|
|
195
|
+
"contentMaxWidth": "90rem",
|
|
196
|
+
"contentPaddingInline": "1rem",
|
|
197
|
+
"measure": "40rem",
|
|
198
|
+
"sectionSpace": "4rem",
|
|
199
|
+
"sectionSpaceShallow": "1.5rem",
|
|
200
|
+
"sectionSpaceDeep": "8rem",
|
|
201
|
+
"stripSpace": "4rem",
|
|
202
|
+
"gridGapInline": "1rem",
|
|
203
|
+
"gridGapBlock": "1rem",
|
|
204
|
+
"pageMargin": "1rem"
|
|
205
|
+
},
|
|
206
|
+
"components": {
|
|
207
|
+
"borderWidth": "1px",
|
|
208
|
+
"barThickness": "0.1875rem",
|
|
209
|
+
"radius": "0rem",
|
|
210
|
+
"controlBlockPadding": "0.5rem",
|
|
211
|
+
"controlCompactBlockPadding": "0.25rem",
|
|
212
|
+
"controlInlinePadding": "1rem",
|
|
213
|
+
"controlInlinePaddingAction": "1rem",
|
|
214
|
+
"controlInlinePaddingField": "0.5rem",
|
|
215
|
+
"controlVisualSize": "1rem",
|
|
216
|
+
"fieldGap": "0.5rem",
|
|
217
|
+
"panelPaddingInline": "1rem",
|
|
218
|
+
"panelPaddingBlock": "1rem",
|
|
219
|
+
"accordionIndent": "1.5rem"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type BuiltInThemeName, type PresetName, type TierName } from "./tier-registry.js";
|
|
2
|
+
export { isPresetName, isTierName, normalizeBuiltInThemeName, presetDescriptions, presetNames, tierDescriptions, tierNames } from "./tier-registry.js";
|
|
3
|
+
export type { BuiltInThemeName, PresetName, TierName } from "./tier-registry.js";
|
|
4
|
+
export declare function resolveTierPath(name: TierName): string;
|
|
5
|
+
export declare function resolvePresetPath(name: PresetName): string;
|
|
6
|
+
export declare function resolveBuiltInThemePath(name: BuiltInThemeName): string;
|
package/dist/presets.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { isTierName } from "./tier-registry.js";
|
|
4
|
+
export { isPresetName, isTierName, normalizeBuiltInThemeName, presetDescriptions, presetNames, tierDescriptions, tierNames } from "./tier-registry.js";
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const tierConfigPaths = {
|
|
7
|
+
editorial: path.resolve(__dirname, "..", "config", "tiers", "editorial.json"),
|
|
8
|
+
documentation: path.resolve(__dirname, "..", "config", "tiers", "documentation.json"),
|
|
9
|
+
app: path.resolve(__dirname, "..", "config", "tiers", "app.json"),
|
|
10
|
+
os: path.resolve(__dirname, "..", "config", "tiers", "os.json")
|
|
11
|
+
};
|
|
12
|
+
const presetConfigPaths = {
|
|
13
|
+
prose: tierConfigPaths.editorial,
|
|
14
|
+
"app-tier": tierConfigPaths.app
|
|
15
|
+
};
|
|
16
|
+
export function resolveTierPath(name) {
|
|
17
|
+
return tierConfigPaths[name];
|
|
18
|
+
}
|
|
19
|
+
export function resolvePresetPath(name) {
|
|
20
|
+
return presetConfigPaths[name];
|
|
21
|
+
}
|
|
22
|
+
export function resolveBuiltInThemePath(name) {
|
|
23
|
+
if (isTierName(name)) {
|
|
24
|
+
return resolveTierPath(name);
|
|
25
|
+
}
|
|
26
|
+
return resolvePresetPath(name);
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface RangeControlsInitOptions {
|
|
2
|
+
root?: ParentNode;
|
|
3
|
+
rangeSelector?: string;
|
|
4
|
+
numberSelector?: string;
|
|
5
|
+
wrapperSelector?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function updateRangeFill(range: HTMLInputElement): void;
|
|
8
|
+
export declare function setupRangeControl(range: HTMLInputElement, options?: RangeControlsInitOptions): void;
|
|
9
|
+
export declare function initRangeControls(options?: RangeControlsInitOptions): void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const DEFAULT_RANGE_SELECTOR = "input[type='range']";
|
|
2
|
+
const DEFAULT_NUMBER_SELECTOR = ".bf-slider-input";
|
|
3
|
+
const DEFAULT_WRAPPER_SELECTOR = ".bf-slider";
|
|
4
|
+
function clamp(value, min, max) {
|
|
5
|
+
return Math.min(Math.max(value, min), max);
|
|
6
|
+
}
|
|
7
|
+
function getBounds(input) {
|
|
8
|
+
const min = Number(input.min || 0);
|
|
9
|
+
const max = Number(input.max || 100);
|
|
10
|
+
if (Number.isNaN(min) || Number.isNaN(max) || min === max) {
|
|
11
|
+
return { min: 0, max: 100 };
|
|
12
|
+
}
|
|
13
|
+
return { min, max };
|
|
14
|
+
}
|
|
15
|
+
export function updateRangeFill(range) {
|
|
16
|
+
const { min, max } = getBounds(range);
|
|
17
|
+
const value = Number(range.value || min);
|
|
18
|
+
const percent = ((clamp(value, min, max) - min) / (max - min)) * 100;
|
|
19
|
+
range.style.setProperty("--bf-slider-fill-percent", `${percent}%`);
|
|
20
|
+
}
|
|
21
|
+
function findPairedNumberInput(range, options) {
|
|
22
|
+
const wrapperSelector = options.wrapperSelector ?? DEFAULT_WRAPPER_SELECTOR;
|
|
23
|
+
const numberSelector = options.numberSelector ?? DEFAULT_NUMBER_SELECTOR;
|
|
24
|
+
const wrapper = range.closest(wrapperSelector);
|
|
25
|
+
if (!wrapper) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return wrapper.querySelector(numberSelector);
|
|
29
|
+
}
|
|
30
|
+
export function setupRangeControl(range, options = {}) {
|
|
31
|
+
if (range.dataset.bfRangeInitialized === "true") {
|
|
32
|
+
updateRangeFill(range);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const pairedNumberInput = findPairedNumberInput(range, options);
|
|
36
|
+
updateRangeFill(range);
|
|
37
|
+
if (pairedNumberInput) {
|
|
38
|
+
pairedNumberInput.value = range.value;
|
|
39
|
+
const syncFromNumberInput = () => {
|
|
40
|
+
const { min, max } = getBounds(range);
|
|
41
|
+
const numericValue = Number(pairedNumberInput.value || range.value);
|
|
42
|
+
const nextValue = clamp(Number.isNaN(numericValue) ? Number(range.value) : numericValue, min, max);
|
|
43
|
+
range.value = String(nextValue);
|
|
44
|
+
pairedNumberInput.value = String(nextValue);
|
|
45
|
+
updateRangeFill(range);
|
|
46
|
+
};
|
|
47
|
+
pairedNumberInput.addEventListener("input", syncFromNumberInput);
|
|
48
|
+
pairedNumberInput.addEventListener("change", syncFromNumberInput);
|
|
49
|
+
}
|
|
50
|
+
range.addEventListener("input", () => {
|
|
51
|
+
updateRangeFill(range);
|
|
52
|
+
if (pairedNumberInput) {
|
|
53
|
+
pairedNumberInput.value = range.value;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
range.addEventListener("change", () => {
|
|
57
|
+
updateRangeFill(range);
|
|
58
|
+
if (pairedNumberInput) {
|
|
59
|
+
pairedNumberInput.value = range.value;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
range.dataset.bfRangeInitialized = "true";
|
|
63
|
+
}
|
|
64
|
+
export function initRangeControls(options = {}) {
|
|
65
|
+
const root = options.root ?? document;
|
|
66
|
+
const rangeSelector = options.rangeSelector ?? DEFAULT_RANGE_SELECTOR;
|
|
67
|
+
const ranges = root.querySelectorAll(rangeSelector);
|
|
68
|
+
ranges.forEach(range => {
|
|
69
|
+
if (range.type === "range") {
|
|
70
|
+
setupRangeControl(range, options);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
const APPLICATION_SELECTOR = ".bf-application";
|
|
2
|
+
const PINNED_ASIDE_SELECTOR = ".bf-aside.is-pinned";
|
|
3
|
+
const HANDLE_SELECTOR = ".bf-application-aside-resize-handle";
|
|
4
|
+
const DEFAULT_STEP_PX = 16;
|
|
5
|
+
const DEFAULT_STORAGE_PREFIX = "baseline-foundry-aside-width";
|
|
6
|
+
const RESIZING_CLASS = "is-resizing-aside";
|
|
7
|
+
function queryAllWithinRoot(root, selector) {
|
|
8
|
+
const elements = Array.from(root.querySelectorAll(selector));
|
|
9
|
+
if (root instanceof Element && root.matches(selector)) {
|
|
10
|
+
elements.unshift(root);
|
|
11
|
+
}
|
|
12
|
+
return elements;
|
|
13
|
+
}
|
|
14
|
+
function getApplications(root) {
|
|
15
|
+
return queryAllWithinRoot(root, APPLICATION_SELECTOR);
|
|
16
|
+
}
|
|
17
|
+
function resolveCssLengthPx(context, cssValue, fallbackPx) {
|
|
18
|
+
const trimmedValue = cssValue.trim();
|
|
19
|
+
if (!trimmedValue) {
|
|
20
|
+
return fallbackPx;
|
|
21
|
+
}
|
|
22
|
+
const probe = document.createElement("div");
|
|
23
|
+
probe.style.border = "0";
|
|
24
|
+
probe.style.inlineSize = trimmedValue;
|
|
25
|
+
probe.style.margin = "0";
|
|
26
|
+
probe.style.opacity = "0";
|
|
27
|
+
probe.style.padding = "0";
|
|
28
|
+
probe.style.pointerEvents = "none";
|
|
29
|
+
probe.style.position = "absolute";
|
|
30
|
+
probe.style.visibility = "hidden";
|
|
31
|
+
context.appendChild(probe);
|
|
32
|
+
const resolvedPx = probe.getBoundingClientRect().width;
|
|
33
|
+
probe.remove();
|
|
34
|
+
return Number.isFinite(resolvedPx) && resolvedPx > 0 ? resolvedPx : fallbackPx;
|
|
35
|
+
}
|
|
36
|
+
function resolveNumericDatasetValue(...values) {
|
|
37
|
+
for (const value of values) {
|
|
38
|
+
if (!value) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const parsed = Number.parseFloat(value);
|
|
42
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
43
|
+
return parsed;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function getPinnedAside(application) {
|
|
49
|
+
return Array.from(application.children).find((child) => {
|
|
50
|
+
return child instanceof HTMLElement && child.matches(PINNED_ASIDE_SELECTOR);
|
|
51
|
+
}) ?? application.querySelector(PINNED_ASIDE_SELECTOR);
|
|
52
|
+
}
|
|
53
|
+
function getResizeHandle(application, aside) {
|
|
54
|
+
return aside?.querySelector(HANDLE_SELECTOR)
|
|
55
|
+
?? application.querySelector(HANDLE_SELECTOR)
|
|
56
|
+
?? null;
|
|
57
|
+
}
|
|
58
|
+
function isPinnedResizableAside(aside) {
|
|
59
|
+
return Boolean(aside
|
|
60
|
+
&& aside.classList.contains("is-pinned")
|
|
61
|
+
&& !aside.classList.contains("is-overlay")
|
|
62
|
+
&& !aside.classList.contains("is-drawer")
|
|
63
|
+
&& !aside.classList.contains("is-collapsed"));
|
|
64
|
+
}
|
|
65
|
+
function getStorageKey(application, aside, handle) {
|
|
66
|
+
const configuredKey = handle.dataset.asideResizeStorageKey
|
|
67
|
+
?? aside.dataset.asideResizeStorageKey
|
|
68
|
+
?? application.dataset.asideResizeStorageKey;
|
|
69
|
+
if (configuredKey === "") {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (configuredKey) {
|
|
73
|
+
return configuredKey;
|
|
74
|
+
}
|
|
75
|
+
const identity = aside.id || application.id;
|
|
76
|
+
if (!identity) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return `${DEFAULT_STORAGE_PREFIX}:${location.pathname}:${identity}`;
|
|
80
|
+
}
|
|
81
|
+
function getStepPx(application, aside, handle) {
|
|
82
|
+
return resolveNumericDatasetValue(handle.dataset.asideResizeStep, aside.dataset.asideResizeStep, application.dataset.asideResizeStep) ?? DEFAULT_STEP_PX;
|
|
83
|
+
}
|
|
84
|
+
function getWidthBounds(application, aside, handle) {
|
|
85
|
+
const computedStyle = getComputedStyle(application);
|
|
86
|
+
const minFromDataset = handle.dataset.asideResizeMin
|
|
87
|
+
?? aside.dataset.asideResizeMin
|
|
88
|
+
?? application.dataset.asideResizeMin;
|
|
89
|
+
const maxFromDataset = handle.dataset.asideResizeMax
|
|
90
|
+
?? aside.dataset.asideResizeMax
|
|
91
|
+
?? application.dataset.asideResizeMax;
|
|
92
|
+
const minValue = minFromDataset
|
|
93
|
+
?? computedStyle.getPropertyValue("--bf-app-aside-width-min")
|
|
94
|
+
?? computedStyle.getPropertyValue("--bf-application-aside-width-min")
|
|
95
|
+
?? computedStyle.getPropertyValue("--bf-app-drawer-width-small")
|
|
96
|
+
?? computedStyle.getPropertyValue("--bf-application-drawer-width-small");
|
|
97
|
+
const maxValue = maxFromDataset
|
|
98
|
+
?? computedStyle.getPropertyValue("--bf-app-aside-width-max")
|
|
99
|
+
?? computedStyle.getPropertyValue("--bf-application-aside-width-max")
|
|
100
|
+
?? computedStyle.getPropertyValue("--bf-app-drawer-width-medium-max")
|
|
101
|
+
?? computedStyle.getPropertyValue("--bf-application-drawer-width-medium-max");
|
|
102
|
+
const minPx = resolveCssLengthPx(application, minValue, 240);
|
|
103
|
+
const maxPx = resolveCssLengthPx(application, maxValue, 640);
|
|
104
|
+
return {
|
|
105
|
+
minPx,
|
|
106
|
+
maxPx: Math.max(minPx, maxPx)
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function getCurrentWidthPx(application, aside) {
|
|
110
|
+
const measuredWidth = aside.getBoundingClientRect().width;
|
|
111
|
+
if (measuredWidth > 0) {
|
|
112
|
+
return measuredWidth;
|
|
113
|
+
}
|
|
114
|
+
const computedStyle = getComputedStyle(application);
|
|
115
|
+
return resolveCssLengthPx(application, computedStyle.getPropertyValue("--bf-app-aside-width")
|
|
116
|
+
|| computedStyle.getPropertyValue("--bf-application-aside-width"), 465);
|
|
117
|
+
}
|
|
118
|
+
function clamp(value, minPx, maxPx) {
|
|
119
|
+
return Math.max(minPx, Math.min(maxPx, value));
|
|
120
|
+
}
|
|
121
|
+
function setHandleInteractivity(handle, enabled) {
|
|
122
|
+
handle.setAttribute("aria-disabled", String(!enabled));
|
|
123
|
+
handle.tabIndex = enabled ? 0 : -1;
|
|
124
|
+
}
|
|
125
|
+
function updateHandleA11y(application, aside, handle, widthPx = getCurrentWidthPx(application, aside)) {
|
|
126
|
+
if (!handle.hasAttribute("role")) {
|
|
127
|
+
handle.setAttribute("role", "separator");
|
|
128
|
+
}
|
|
129
|
+
if (!handle.hasAttribute("aria-orientation")) {
|
|
130
|
+
handle.setAttribute("aria-orientation", "vertical");
|
|
131
|
+
}
|
|
132
|
+
if (!handle.hasAttribute("aria-label")) {
|
|
133
|
+
handle.setAttribute("aria-label", "Resize panel");
|
|
134
|
+
}
|
|
135
|
+
if (aside.id && !handle.hasAttribute("aria-controls")) {
|
|
136
|
+
handle.setAttribute("aria-controls", aside.id);
|
|
137
|
+
}
|
|
138
|
+
const enabled = isPinnedResizableAside(aside);
|
|
139
|
+
setHandleInteractivity(handle, enabled);
|
|
140
|
+
if (!enabled) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const { minPx, maxPx } = getWidthBounds(application, aside, handle);
|
|
144
|
+
handle.setAttribute("aria-valuemin", String(Math.round(minPx)));
|
|
145
|
+
handle.setAttribute("aria-valuemax", String(Math.round(maxPx)));
|
|
146
|
+
handle.setAttribute("aria-valuenow", String(Math.round(clamp(widthPx, minPx, maxPx))));
|
|
147
|
+
}
|
|
148
|
+
function readPersistedWidth(storageKey) {
|
|
149
|
+
if (!storageKey) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const rawWidth = localStorage.getItem(storageKey);
|
|
154
|
+
if (!rawWidth) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
const parsedWidth = Number.parseFloat(rawWidth);
|
|
158
|
+
return Number.isFinite(parsedWidth) ? parsedWidth : null;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function writePersistedWidth(storageKey, widthPx) {
|
|
165
|
+
if (!storageKey) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
localStorage.setItem(storageKey, String(Math.round(widthPx)));
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// Ignore storage failures so the shell still works in restricted environments.
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function clearPersistedWidth(storageKey) {
|
|
176
|
+
if (!storageKey) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
localStorage.removeItem(storageKey);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Ignore storage failures so reset still works visually.
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function applyWidth(application, aside, handle, storageKey, widthPx, persist) {
|
|
187
|
+
const { minPx, maxPx } = getWidthBounds(application, aside, handle);
|
|
188
|
+
const nextWidthPx = clamp(widthPx, minPx, maxPx);
|
|
189
|
+
application.style.setProperty("--bf-app-aside-width", `${nextWidthPx}px`);
|
|
190
|
+
application.style.setProperty("--bf-application-aside-width", `${nextWidthPx}px`);
|
|
191
|
+
updateHandleA11y(application, aside, handle, nextWidthPx);
|
|
192
|
+
if (persist) {
|
|
193
|
+
writePersistedWidth(storageKey, nextWidthPx);
|
|
194
|
+
}
|
|
195
|
+
return nextWidthPx;
|
|
196
|
+
}
|
|
197
|
+
function resetWidth(application, aside, handle, storageKey) {
|
|
198
|
+
clearPersistedWidth(storageKey);
|
|
199
|
+
application.style.removeProperty("--bf-app-aside-width");
|
|
200
|
+
application.style.removeProperty("--bf-application-aside-width");
|
|
201
|
+
updateHandleA11y(application, aside, handle);
|
|
202
|
+
}
|
|
203
|
+
function syncHandleToRenderedWidth(application, aside, handle) {
|
|
204
|
+
updateHandleA11y(application, aside, handle, getCurrentWidthPx(application, aside));
|
|
205
|
+
}
|
|
206
|
+
function setupApplication(application) {
|
|
207
|
+
const aside = getPinnedAside(application);
|
|
208
|
+
const handle = getResizeHandle(application, aside);
|
|
209
|
+
if (!aside || !handle) {
|
|
210
|
+
return () => { };
|
|
211
|
+
}
|
|
212
|
+
const storageKey = getStorageKey(application, aside, handle);
|
|
213
|
+
const stepPx = getStepPx(application, aside, handle);
|
|
214
|
+
const persistedWidth = readPersistedWidth(storageKey);
|
|
215
|
+
if (persistedWidth !== null) {
|
|
216
|
+
applyWidth(application, aside, handle, storageKey, persistedWidth, false);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
updateHandleA11y(application, aside, handle);
|
|
220
|
+
}
|
|
221
|
+
let initialSyncFrameId = 0;
|
|
222
|
+
const onWindowLoad = () => {
|
|
223
|
+
syncHandleToRenderedWidth(application, aside, handle);
|
|
224
|
+
};
|
|
225
|
+
initialSyncFrameId = window.requestAnimationFrame(() => {
|
|
226
|
+
syncHandleToRenderedWidth(application, aside, handle);
|
|
227
|
+
});
|
|
228
|
+
window.addEventListener("load", onWindowLoad, { once: true });
|
|
229
|
+
const onDoubleClick = () => {
|
|
230
|
+
resetWidth(application, aside, handle, storageKey);
|
|
231
|
+
};
|
|
232
|
+
const onKeyDown = (event) => {
|
|
233
|
+
if (!isPinnedResizableAside(aside)) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const currentWidthPx = getCurrentWidthPx(application, aside);
|
|
237
|
+
const { minPx, maxPx } = getWidthBounds(application, aside, handle);
|
|
238
|
+
const adjustedStepPx = event.shiftKey ? stepPx * 3 : stepPx;
|
|
239
|
+
if (event.key === "ArrowLeft") {
|
|
240
|
+
applyWidth(application, aside, handle, storageKey, currentWidthPx + adjustedStepPx, true);
|
|
241
|
+
event.preventDefault();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (event.key === "ArrowRight") {
|
|
245
|
+
applyWidth(application, aside, handle, storageKey, currentWidthPx - adjustedStepPx, true);
|
|
246
|
+
event.preventDefault();
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (event.key === "Home") {
|
|
250
|
+
applyWidth(application, aside, handle, storageKey, minPx, true);
|
|
251
|
+
event.preventDefault();
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (event.key === "End") {
|
|
255
|
+
applyWidth(application, aside, handle, storageKey, maxPx, true);
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
const onPointerDown = (event) => {
|
|
260
|
+
if (event.button !== 0 || !isPinnedResizableAside(aside)) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
event.preventDefault();
|
|
264
|
+
const shellRect = application.getBoundingClientRect();
|
|
265
|
+
application.classList.add(RESIZING_CLASS);
|
|
266
|
+
handle.setPointerCapture(event.pointerId);
|
|
267
|
+
let finished = false;
|
|
268
|
+
const onPointerMove = (moveEvent) => {
|
|
269
|
+
const nextWidthPx = shellRect.right - moveEvent.clientX;
|
|
270
|
+
applyWidth(application, aside, handle, storageKey, nextWidthPx, false);
|
|
271
|
+
};
|
|
272
|
+
const finishResize = () => {
|
|
273
|
+
if (finished) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
finished = true;
|
|
277
|
+
application.classList.remove(RESIZING_CLASS);
|
|
278
|
+
applyWidth(application, aside, handle, storageKey, getCurrentWidthPx(application, aside), true);
|
|
279
|
+
handle.removeEventListener("pointermove", onPointerMove);
|
|
280
|
+
handle.removeEventListener("pointerup", finishResize);
|
|
281
|
+
handle.removeEventListener("pointercancel", finishResize);
|
|
282
|
+
handle.removeEventListener("lostpointercapture", finishResize);
|
|
283
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
284
|
+
window.removeEventListener("pointerup", finishResize);
|
|
285
|
+
window.removeEventListener("pointercancel", finishResize);
|
|
286
|
+
if (handle.hasPointerCapture(event.pointerId)) {
|
|
287
|
+
handle.releasePointerCapture(event.pointerId);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
handle.addEventListener("pointermove", onPointerMove);
|
|
291
|
+
handle.addEventListener("pointerup", finishResize, { once: true });
|
|
292
|
+
handle.addEventListener("pointercancel", finishResize, { once: true });
|
|
293
|
+
handle.addEventListener("lostpointercapture", finishResize, { once: true });
|
|
294
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
295
|
+
window.addEventListener("pointerup", finishResize, { once: true });
|
|
296
|
+
window.addEventListener("pointercancel", finishResize, { once: true });
|
|
297
|
+
};
|
|
298
|
+
const onWindowResize = () => {
|
|
299
|
+
if (isPinnedResizableAside(aside)) {
|
|
300
|
+
applyWidth(application, aside, handle, storageKey, getCurrentWidthPx(application, aside), false);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
updateHandleA11y(application, aside, handle);
|
|
304
|
+
};
|
|
305
|
+
handle.addEventListener("dblclick", onDoubleClick);
|
|
306
|
+
handle.addEventListener("keydown", onKeyDown);
|
|
307
|
+
handle.addEventListener("pointerdown", onPointerDown);
|
|
308
|
+
window.addEventListener("resize", onWindowResize);
|
|
309
|
+
return () => {
|
|
310
|
+
if (initialSyncFrameId !== 0) {
|
|
311
|
+
window.cancelAnimationFrame(initialSyncFrameId);
|
|
312
|
+
}
|
|
313
|
+
window.removeEventListener("load", onWindowLoad);
|
|
314
|
+
handle.removeEventListener("dblclick", onDoubleClick);
|
|
315
|
+
handle.removeEventListener("keydown", onKeyDown);
|
|
316
|
+
handle.removeEventListener("pointerdown", onPointerDown);
|
|
317
|
+
window.removeEventListener("resize", onWindowResize);
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
export function initResizableAsides(options = {}) {
|
|
321
|
+
const root = options.root ?? document;
|
|
322
|
+
const cleanups = getApplications(root).map(setupApplication);
|
|
323
|
+
return () => {
|
|
324
|
+
for (const cleanup of cleanups) {
|
|
325
|
+
cleanup();
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|