Skip to content

Commit

Permalink
Fix bug where style override loses to default styles for class
Browse files Browse the repository at this point in the history
== npm run size ==

JS transerSize (compressed):

* Before : 2248
* After  : 2245 (-3 B)

CSS:
* Before : 1921
* After  : 1954 (+33B)
  • Loading branch information
Krinkle committed Aug 1, 2024
1 parent 32ed625 commit 48296e0
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 15 deletions.
11 changes: 11 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Contribute to typesense-minibar

## Implementation notes

* The styles for `typesense-minibar` as web component, and `.tsmb-form` class name are kept independent (that is, the web component does not auto-add the class name).

This is done for two reasons:

1. Avoid selector conflict for Style API.
If we were to add `class="tsmb-form"` in the web component, it would mean `typesense-minibar form` and `.tsmb-form` both match. This makes the `typesense-minibar form` selector impsosible to override in CSS for downstream users, because our defaults for `.tsmb-form` (weight 0010) would continue to "win" the cascade, as being a stronger selector than `typesense-minibar form` (weight 0002).
2. Avoid a FOUC.
The element should render identically and without reflows both before and after JavaScript loads. During local development it's easy to miss a FOUC if it fixes itself once JavaScript loads. By not auto-correcting these, the bugs are more obvious and we fix them.

## Internal API

```js
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,14 @@ Notes:

If you create or insert the element dynamically with JavaScript, it is recommended to write the form as a web component instead, like so:
```html
<typescript-minibar>
<typesense-minibar>
<form ..>..</form>
</typescript-minibar>
</typesense-minibar>
```

Web components automatically activate the relevant JavaScript, no matter when they are inserted on the page.

By default, typescript-minibar.js also makes sure that any `<form class="tsmb-form">` elements on the page are hydrated and activated. This should catch any static element on the page (i.e. before "document ready", or the DOMContentLoaded event). This works internally by levering the fact that script execution is naturally deferred until the document is ready, via the `defer` and `type="module"` attributes on the `<script>` tag.
By default, typesense-minibar.js also makes sure that any `<form class="tsmb-form">` elements on the page are hydrated and activated. This should catch any static element on the page (i.e. before "document ready", or the DOMContentLoaded event). This works internally by levering the fact that script execution is naturally deferred until the document is ready, via the `defer` and `type="module"` attributes on the `<script>` tag.

* How does this prevent JavaScript errors in older browsers? What about ES5?

Expand Down
14 changes: 10 additions & 4 deletions demo/demo-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,23 @@ header > * {
background-image: url(../assets/logo-text-dark.svg);
}

header .tsmb-form {
width: 30em;
header .tsmb-form,
header typesense-minibar {
--tsmb-color-base-background: #691c69;
--tsmb-color-base30: var(--tsmb-color-primary90);
--tsmb-color-base50: #c090c0;
--tsmb-color-base90: #c090c0;
--tsmb-size-listbox-width: calc(min(50rem, 80vw));
}
header .tsmb-form:not(:focus-within)::before {
header .tsmb-form,
header typesense-minibar form {
width: 30em;
}
header .tsmb-form:not(:focus-within)::before,
header typesense-minibar form:not(:focus-within)::before {
filter: invert();
}
header .tsmb-form input[type=search] {
header .tsmb-form input[type=search],
header typesense-minibar input[type=search] {
border: none;
}
10 changes: 10 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@
<input type="hidden" name="sites" value="jquery.com">
</form>
</header>
<header>
<span class="demo-logo"></span>
<!-- Web Component -->
<typesense-minibar class="demo-right-form">
<form role="search" data-origin="https://typesense.jquery.com" data-collection="jquery_com" data-key="Zh8mMgohXECel9wjPwqT7lekLSG3OCgz" data-foot="true" data-group="true" action="https://duckduckgo.com">
<input type="search" name="q" aria-label="Search" placeholder="Search..." autocomplete="off">
<input type="hidden" name="sites" value="jquery.com">
</form>
</typesense-minibar>
</header>
<main>
<h2>Web Component</h2>
<typesense-minibar>
Expand Down
2 changes: 1 addition & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ QUnit.module('typesense-minibar', hooks => {
const element = parseHTML('<typesense-minibar><form><input type="search"></form></typesense-minibar>');
document.querySelector('#qunit-fixture').append(element);
const form = element.querySelector('form');
assert.equal(form.className, 'tsmb-form tsmb-form--slash', 'set form class');
assert.equal(form.className, 'tsmb-form--slash', 'set form class');

const input = form.firstChild;
const listbox = element.querySelector('[role=listbox]');
Expand Down
19 changes: 13 additions & 6 deletions typesense-minibar.css
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ typesense-minibar form::before {
color: var(--tsmb-color-base90);
}

.tsmb-form [role=listbox] {
.tsmb-form [role=listbox],
typesense-minibar [role=listbox] {
position: absolute;
z-index: 10;
right: var(--tsmb-size-listbox-right);
Expand All @@ -163,29 +164,35 @@ typesense-minibar form::before {
border-bottom: var(--tsmb-size-edge) solid var(--tsmb-color-focus90);
}

.tsmb-form [role=option] a {
.tsmb-form [role=option] a,
typesense-minibar [role=option] a {
display: block;
padding: var(--tsmb-size-base);
text-decoration: none;
border-left: var(--tsmb-size-highlight) solid transparent;
}

.tsmb-form:not([data-group=true]) [role=option]:not(:first-child) a {
.tsmb-form:not([data-group=true]) [role=option]:not(:first-child) a,
typesense-minibar form:not([data-group=true]) [role=option]:not(:first-child) a {
border-top: var(--tsmb-size-edge) solid var(--tsmb-color-focus90);
}

.tsmb-form[data-group=true] [role=option] a {
.tsmb-form[data-group=true] [role=option] a,
typesense-minibar form[data-group=true] [role=option] a {
margin: 0 var(--tsmb-size-base);
padding: var(--tsmb-size-sm);
}

.tsmb-form [role=option] a:hover,
.tsmb-form [role=option][aria-selected=true] a {
.tsmb-form [role=option][aria-selected=true] a,
typesense-minibar [role=option] a:hover,
typesense-minibar [role=option][aria-selected=true] a {
background: var(--tsmb-color-primary90);
border-left-color: var(--tsmb-color-primary50);
}

.tsmb-form [role=option] mark {
.tsmb-form [role=option] mark,
typesense-minibar [role=option] mark {
background: none;
color: inherit;
font-style: normal;
Expand Down
1 change: 0 additions & 1 deletion typesense-minibar.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ globalThis.tsminibar = function tsminibar (form) {

function connect () {
document.addEventListener('click', onDocClick);
form.classList.add('tsmb-form');
if (form.dataset.slash !== 'false') {
document.addEventListener('keydown', onDocSlash);
form.classList.add('tsmb-form--slash');
Expand Down

0 comments on commit 48296e0

Please sign in to comment.