Skip to content

Commit 8bea50c

Browse files
committed
handle styling of dropbox using style pilfering
1 parent 3dda2f3 commit 8bea50c

File tree

3 files changed

+52
-4
lines changed

3 files changed

+52
-4
lines changed

client/django-formset/DjangoFormset.scss

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
@use "sass:list";
2-
@import "dropbox";
32
@import "colors";
43

54
input::placeholder, select::placeholder {
@@ -210,7 +209,6 @@ django-formset {
210209
}
211210
}
212211
}
213-
@include Dropbox;
214212
}
215213

216214
[is^="django-"][hidden] {

client/django-formset/_dropbox.scss renamed to client/django-formset/FileUploadWidget.scss

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
@mixin Dropbox {
1+
django-formset .dj-control-panel:has(input[type="file"]) {
2+
--dummy-style: none; // required by FileUploadWidget.transferStyles()
3+
24
figure.dj-dropbox {
35
all: unset;
46
display: inline-flex;
@@ -8,7 +10,12 @@
810
padding: 1px;
911
height: 8rem;
1012
max-width: 100%;
11-
outline: rgb(128, 128, 128) thin dotted;
13+
outline: var(--outline-color) thin dotted;
14+
15+
&:has(> .dj-empty-item) {
16+
outline: var(--outline-color) 2px dashed;
17+
border-radius: 0.25rem;
18+
}
1219

1320
> div.dj-empty-item {
1421
flex-grow: 1;
@@ -69,5 +76,6 @@
6976
}
7077

7178
}
79+
7280
}
7381
}

client/django-formset/FileUploadWidget.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import template from 'lodash.template';
2+
import {StyleHelpers} from './helpers';
3+
import styles from './FileUploadWidget.scss';
24

35

46
export class FileUploadWidget {
@@ -12,6 +14,8 @@ export class FileUploadWidget {
1214
private readonly initialData: Object[];
1315
private readonly initialRequired: boolean;
1416
private readonly maxUploadSize: number;
17+
private readonly baseSelector = 'django-formset .dj-control-panel:has(input[type="file"])';
18+
private readonly styleSheet: CSSStyleSheet;
1519
public readonly inputElement: HTMLInputElement;
1620
public uploadedFiles: Object[];
1721

@@ -44,6 +48,7 @@ export class FileUploadWidget {
4448
this.observer = new MutationObserver(mutationsList => this.attributesChanged(mutationsList));
4549
this.observer.observe(this.inputElement, {attributes: true});
4650
this.chooseFileButton.disabled = inputElement.disabled;
51+
this.styleSheet = StyleHelpers.stylesAreInstalled(this.baseSelector) ?? this.transferStyles();
4752

4853
const initialData = document.getElementById(`initial_${inputElement.id}`);
4954
if (initialData?.textContent) {
@@ -228,6 +233,43 @@ export class FileUploadWidget {
228233
}
229234
}
230235

236+
private transferStyles() : CSSStyleSheet {
237+
const declaredStyles = document.createElement('style');
238+
declaredStyles.innerText = styles;
239+
document.head.appendChild(declaredStyles);
240+
if (!declaredStyles.sheet)
241+
throw new Error("Could not create <style> element");
242+
this.inputElement.style.transition = 'none'; // prevent transition while pilfering styles
243+
let loaded = false;
244+
for (let index = 0; declaredStyles.sheet && index < declaredStyles.sheet.cssRules.length; index++) {
245+
const cssRule = declaredStyles.sheet.cssRules.item(index) as CSSStyleRule;
246+
const selector = cssRule.selectorText.trim();
247+
let extraStyles = '';
248+
switch (selector) {
249+
case this.baseSelector:
250+
loaded = true;
251+
break;
252+
default:
253+
break;
254+
}
255+
if (extraStyles) {
256+
declaredStyles.sheet.insertRule(`${selector}{${extraStyles}}`, ++index);
257+
}
258+
}
259+
this.inputElement.style.transition = '';
260+
StyleHelpers.pushMediaQueryStyles(
261+
declaredStyles.sheet,
262+
this.baseSelector,
263+
{
264+
'--outline-color': 'outline-color',
265+
},
266+
this.inputElement,
267+
);
268+
if (!loaded)
269+
throw new Error(`Could not load styles for ${this.baseSelector}`);
270+
return declaredStyles.sheet as CSSStyleSheet;
271+
}
272+
231273
public inProgress(): boolean {
232274
return !!this.inputElement.files && this.inputElement.files.length > 0 && !this.uploadedFiles.length;
233275
}

0 commit comments

Comments
 (0)