@jschofield/quick-search 0.2.0
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/README.md +83 -0
- package/dist/assets/index.css +1 -0
- package/dist/assets/index.js +266 -0
- package/dist/index.html +136 -0
- package/dist/vite.svg +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# @jschofield/quick-search
|
|
2
|
+
|
|
3
|
+
A Cmd+K search modal web component built with [Lit](https://lit.dev/) and [Fuse.js](https://www.fusejs.io/). Provides fuzzy search over page content with keyboard navigation.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @jschofield/quick-search
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Peer dependencies
|
|
12
|
+
|
|
13
|
+
This component requires the following peer dependency:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install lit
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Peer | Version |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `lit` | `^3.0.0` |
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<script type="module">
|
|
27
|
+
import '@jschofield/quick-search';
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<quick-search></quick-search>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Without a bundler
|
|
34
|
+
|
|
35
|
+
If you're not using a bundler, provide peer dependencies via an import map:
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<script type="importmap">
|
|
39
|
+
{
|
|
40
|
+
"imports": {
|
|
41
|
+
"lit": "https://esm.run/lit",
|
|
42
|
+
"lit/": "https://esm.run/lit/"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
<script type="module" src="https://esm.run/@jschofield/quick-search"></script>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
No attributes needed — drop it in and it works.
|
|
50
|
+
|
|
51
|
+
## How it works
|
|
52
|
+
|
|
53
|
+
1. Fetches `/search-data.json` on first open
|
|
54
|
+
2. Fuzzy-searches by title, excerpt, and categories
|
|
55
|
+
3. Results link directly to matching pages
|
|
56
|
+
|
|
57
|
+
### Data format
|
|
58
|
+
|
|
59
|
+
The component expects a JSON file at `/search-data.json` with this shape:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
[
|
|
63
|
+
{
|
|
64
|
+
"title": "My Post Title",
|
|
65
|
+
"excerpt": "A brief description...",
|
|
66
|
+
"url": "/posts/my-post/",
|
|
67
|
+
"categories": ["javascript", "web-components"]
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Keyboard shortcuts
|
|
73
|
+
|
|
74
|
+
| Key | Action |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `Cmd+K` / `Ctrl+K` | Open search |
|
|
77
|
+
| `Escape` | Close search |
|
|
78
|
+
| `Enter` | Navigate to selected result |
|
|
79
|
+
| Type to search | Fuzzy match across title, excerpt, categories |
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{box-sizing:border-box}body{background:#bcd;min-height:100vh;margin:0;padding:0}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import{LitElement as e,css as t,html as n}from"lit";import{customElement as r,state as i}from"lit/decorators.js";import{createRef as a,ref as o}from"lit/directives/ref.js";import{map as s}from"lit/directives/map.js";import{Task as c}from"@lit/task";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();function l(e){return Array.isArray?Array.isArray(e):b(e)===`[object Array]`}var u=1/0;function d(e){if(typeof e==`string`)return e;let t=e+``;return t==`0`&&1/e==-u?`-0`:t}function f(e){return e==null?``:d(e)}function p(e){return typeof e==`string`}function m(e){return typeof e==`number`}function h(e){return e===!0||e===!1||_(e)&&b(e)==`[object Boolean]`}function g(e){return typeof e==`object`}function _(e){return g(e)&&e!==null}function v(e){return e!=null}function y(e){return!e.trim().length}function b(e){return e==null?e===void 0?`[object Undefined]`:`[object Null]`:Object.prototype.toString.call(e)}var x=`Incorrect 'index' type`,S=e=>`Invalid value for key ${e}`,ee=e=>`Pattern length exceeds max of ${e}.`,C=e=>`Missing ${e} property in key`,w=e=>`Property 'weight' in key '${e}' must be a positive integer`,T=Object.prototype.hasOwnProperty,te=class{constructor(e){this._keys=[],this._keyMap={};let t=0;e.forEach(e=>{let n=E(e);this._keys.push(n),this._keyMap[n.id]=n,t+=n.weight}),this._keys.forEach(e=>{e.weight/=t})}get(e){return this._keyMap[e]}keys(){return this._keys}toJSON(){return JSON.stringify(this._keys)}};function E(e){let t=null,n=null,r=null,i=1,a=null;if(p(e)||l(e))r=e,t=D(e),n=O(e);else{if(!T.call(e,`name`))throw Error(C(`name`));let o=e.name;if(r=o,T.call(e,`weight`)&&(i=e.weight,i<=0))throw Error(w(o));t=D(o),n=O(o),a=e.getFn}return{path:t,id:n,weight:i,src:r,getFn:a}}function D(e){return l(e)?e:e.split(`.`)}function O(e){return l(e)?e.join(`.`):e}function ne(e,t){let n=[],r=!1,i=(e,t,a,o)=>{if(v(e))if(!t[a])n.push(o===void 0?e:{v:e,i:o});else{let s=e[t[a]];if(!v(s))return;if(a===t.length-1&&(p(s)||m(s)||h(s)))n.push(o===void 0?f(s):{v:f(s),i:o});else if(l(s)){r=!0;for(let e=0,n=s.length;e<n;e+=1)i(s[e],t,a+1,e)}else t.length&&i(s,t,a+1,o)}};return i(e,p(t)?t.split(`.`):t,0),r?n:n[0]}var re={includeMatches:!1,findAllMatches:!1,minMatchCharLength:1},ie={isCaseSensitive:!1,ignoreDiacritics:!1,includeScore:!1,keys:[],shouldSort:!0,sortFn:(e,t)=>e.score===t.score?e.idx<t.idx?-1:1:e.score<t.score?-1:1},ae={location:0,threshold:.6,distance:100},oe={useExtendedSearch:!1,getFn:ne,ignoreLocation:!1,ignoreFieldNorm:!1,fieldNormWeight:1},k={...ie,...re,...ae,...oe},se=/[^ ]+/g;function ce(e=1,t=3){let n=new Map,r=10**t;return{get(t){let i=t.match(se).length;if(n.has(i))return n.get(i);let a=1/i**(.5*e),o=parseFloat(Math.round(a*r)/r);return n.set(i,o),o},clear(){n.clear()}}}var A=class{constructor({getFn:e=k.getFn,fieldNormWeight:t=k.fieldNormWeight}={}){this.norm=ce(t,3),this.getFn=e,this.isCreated=!1,this.setIndexRecords()}setSources(e=[]){this.docs=e}setIndexRecords(e=[]){this.records=e}setKeys(e=[]){this.keys=e,this._keysMap={},e.forEach((e,t)=>{this._keysMap[e.id]=t})}create(){this.isCreated||!this.docs.length||(this.isCreated=!0,p(this.docs[0])?this.docs.forEach((e,t)=>{this._addString(e,t)}):this.docs.forEach((e,t)=>{this._addObject(e,t)}),this.norm.clear())}add(e){let t=this.size();p(e)?this._addString(e,t):this._addObject(e,t)}removeAt(e){this.records.splice(e,1);for(let t=e,n=this.size();t<n;t+=1)--this.records[t].i}removeAll(e){for(let t=e.length-1;t>=0;--t)this.records.splice(e[t],1);for(let e=0,t=this.records.length;e<t;e+=1)this.records[e].i=e}getValueForItemAtKeyId(e,t){return e[this._keysMap[t]]}size(){return this.records.length}_addString(e,t){if(!v(e)||y(e))return;let n={v:e,i:t,n:this.norm.get(e)};this.records.push(n)}_addObject(e,t){let n={i:t,$:{}};this.keys.forEach((t,r)=>{let i=t.getFn?t.getFn(e):this.getFn(e,t.path);if(v(i)){if(l(i)){let e=[];for(let t=0,n=i.length;t<n;t+=1){let n=i[t];if(v(n)){if(p(n)){if(!y(n)){let r={v:n,i:t,n:this.norm.get(n)};e.push(r)}}else if(p(n.v)&&!y(n.v)){let t={v:n.v,i:n.i,n:this.norm.get(n.v)};e.push(t)}}}n.$[r]=e}else if(p(i)&&!y(i)){let e={v:i,n:this.norm.get(i)};n.$[r]=e}}}),this.records.push(n)}toJSON(){return{keys:this.keys,records:this.records}}};function j(e,t,{getFn:n=k.getFn,fieldNormWeight:r=k.fieldNormWeight}={}){let i=new A({getFn:n,fieldNormWeight:r});return i.setKeys(e.map(E)),i.setSources(t),i.create(),i}function le(e,{getFn:t=k.getFn,fieldNormWeight:n=k.fieldNormWeight}={}){let{keys:r,records:i}=e,a=new A({getFn:t,fieldNormWeight:n});return a.setKeys(r),a.setIndexRecords(i),a}function ue(e=[],t=k.minMatchCharLength){let n=[],r=-1,i=-1,a=0;for(let o=e.length;a<o;a+=1){let o=e[a];o&&r===-1?r=a:!o&&r!==-1&&(i=a-1,i-r+1>=t&&n.push([r,i]),r=-1)}return e[a-1]&&a-r>=t&&n.push([r,a-1]),n}var M=32;function de(e,t,n,{location:r=k.location,distance:i=k.distance,threshold:a=k.threshold,findAllMatches:o=k.findAllMatches,minMatchCharLength:s=k.minMatchCharLength,includeMatches:c=k.includeMatches,ignoreLocation:l=k.ignoreLocation}={}){if(t.length>M)throw Error(ee(M));let u=t.length,d=e.length,f=Math.max(0,Math.min(r,d)),p=a,m=f,h=(e,t)=>{let n=e/u;if(l)return n;let r=Math.abs(f-t);return i?n+r/i:r?1:n},g=s>1||c,_=g?Array(d):[],v;for(;(v=e.indexOf(t,m))>-1;){let e=h(0,v);if(p=Math.min(e,p),m=v+u,g){let e=0;for(;e<u;)_[v+e]=1,e+=1}}m=-1;let y=[],b=1,x=u+d,S=1<<u-1;for(let t=0;t<u;t+=1){let r=0,i=x;for(;r<i;)h(t,f+i)<=p?r=i:x=i,i=Math.floor((x-r)/2+r);x=i;let a=Math.max(1,f-i+1),s=o?d:Math.min(f+i,d)+u,c=Array(s+2);c[s+1]=(1<<t)-1;for(let r=s;r>=a;--r){let i=r-1,o=n[e[i]];if(g&&(_[i]=+!!o),c[r]=(c[r+1]<<1|1)&o,t&&(c[r]|=(y[r+1]|y[r])<<1|1|y[r+1]),c[r]&S&&(b=h(t,i),b<=p)){if(p=b,m=i,m<=f)break;a=Math.max(1,2*f-m)}}if(h(t+1,f)>p)break;y=c}let C={isMatch:m>=0,score:Math.max(.001,b)};if(g){let e=ue(_,s);e.length?c&&(C.indices=e):C.isMatch=!1}return C}function fe(e){let t={};for(let n=0,r=e.length;n<r;n+=1){let i=e.charAt(n);t[i]=(t[i]||0)|1<<r-n-1}return t}var N=String.prototype.normalize?(e=>e.normalize(`NFD`).replace(/[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F]/g,``)):(e=>e);function pe(e){if(e.length<=1)return e;e.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let t=[e[0]];for(let n=1,r=e.length;n<r;n+=1){let r=t[t.length-1],i=e[n];i[0]<=r[1]+1?r[1]=Math.max(r[1],i[1]):t.push(i)}return t}var P=class{constructor(e,{location:t=k.location,threshold:n=k.threshold,distance:r=k.distance,includeMatches:i=k.includeMatches,findAllMatches:a=k.findAllMatches,minMatchCharLength:o=k.minMatchCharLength,isCaseSensitive:s=k.isCaseSensitive,ignoreDiacritics:c=k.ignoreDiacritics,ignoreLocation:l=k.ignoreLocation}={}){if(this.options={location:t,threshold:n,distance:r,includeMatches:i,findAllMatches:a,minMatchCharLength:o,isCaseSensitive:s,ignoreDiacritics:c,ignoreLocation:l},e=s?e:e.toLowerCase(),e=c?N(e):e,this.pattern=e,this.chunks=[],!this.pattern.length)return;let u=(e,t)=>{this.chunks.push({pattern:e,alphabet:fe(e),startIndex:t})},d=this.pattern.length;if(d>M){let e=0,t=d%M,n=d-t;for(;e<n;)u(this.pattern.substr(e,M),e),e+=M;if(t){let e=d-M;u(this.pattern.substr(e),e)}}else u(this.pattern,0)}searchIn(e){let{isCaseSensitive:t,ignoreDiacritics:n,includeMatches:r}=this.options;if(e=t?e:e.toLowerCase(),e=n?N(e):e,this.pattern===e){let t={isMatch:!0,score:0};return r&&(t.indices=[[0,e.length-1]]),t}let{location:i,distance:a,threshold:o,findAllMatches:s,minMatchCharLength:c,ignoreLocation:l}=this.options,u=[],d=0,f=!1;this.chunks.forEach(({pattern:t,alphabet:n,startIndex:p})=>{let{isMatch:m,score:h,indices:g}=de(e,t,n,{location:i+p,distance:a,threshold:o,findAllMatches:s,minMatchCharLength:c,includeMatches:r,ignoreLocation:l});m&&(f=!0),d+=h,m&&g&&u.push(...g)});let p={isMatch:f,score:f?d/this.chunks.length:1};return f&&r&&(p.indices=pe(u)),p}},F=class{constructor(e){this.pattern=e}static isMultiMatch(e){return I(e,this.multiRegex)}static isSingleMatch(e){return I(e,this.singleRegex)}search(){}};function I(e,t){let n=e.match(t);return n?n[1]:null}var me=class extends F{constructor(e){super(e)}static get type(){return`exact`}static get multiRegex(){return/^="(.*)"$/}static get singleRegex(){return/^=(.*)$/}search(e){let t=e===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}},he=class extends F{constructor(e){super(e)}static get type(){return`inverse-exact`}static get multiRegex(){return/^!"(.*)"$/}static get singleRegex(){return/^!(.*)$/}search(e){let t=e.indexOf(this.pattern)===-1;return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}},ge=class extends F{constructor(e){super(e)}static get type(){return`prefix-exact`}static get multiRegex(){return/^\^"(.*)"$/}static get singleRegex(){return/^\^(.*)$/}search(e){let t=e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}},_e=class extends F{constructor(e){super(e)}static get type(){return`inverse-prefix-exact`}static get multiRegex(){return/^!\^"(.*)"$/}static get singleRegex(){return/^!\^(.*)$/}search(e){let t=!e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}},ve=class extends F{constructor(e){super(e)}static get type(){return`suffix-exact`}static get multiRegex(){return/^"(.*)"\$$/}static get singleRegex(){return/^(.*)\$$/}search(e){let t=e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[e.length-this.pattern.length,e.length-1]}}},ye=class extends F{constructor(e){super(e)}static get type(){return`inverse-suffix-exact`}static get multiRegex(){return/^!"(.*)"\$$/}static get singleRegex(){return/^!(.*)\$$/}search(e){let t=!e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}},L=class extends F{constructor(e,{location:t=k.location,threshold:n=k.threshold,distance:r=k.distance,includeMatches:i=k.includeMatches,findAllMatches:a=k.findAllMatches,minMatchCharLength:o=k.minMatchCharLength,isCaseSensitive:s=k.isCaseSensitive,ignoreDiacritics:c=k.ignoreDiacritics,ignoreLocation:l=k.ignoreLocation}={}){super(e),this._bitapSearch=new P(e,{location:t,threshold:n,distance:r,includeMatches:i,findAllMatches:a,minMatchCharLength:o,isCaseSensitive:s,ignoreDiacritics:c,ignoreLocation:l})}static get type(){return`fuzzy`}static get multiRegex(){return/^"(.*)"$/}static get singleRegex(){return/^(.*)$/}search(e){return this._bitapSearch.searchIn(e)}},R=class extends F{constructor(e){super(e)}static get type(){return`include`}static get multiRegex(){return/^'"(.*)"$/}static get singleRegex(){return/^'(.*)$/}search(e){let t=0,n,r=[],i=this.pattern.length;for(;(n=e.indexOf(this.pattern,t))>-1;)t=n+i,r.push([n,t-1]);let a=!!r.length;return{isMatch:a,score:a?0:1,indices:r}}},z=[me,R,ge,_e,ye,ve,he,L],B=z.length,be=/ +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,xe=`|`;function Se(e,t={}){return e.split(xe).map(e=>{let n=e.trim().split(be).filter(e=>e&&!!e.trim()),r=[];for(let e=0,i=n.length;e<i;e+=1){let i=n[e],a=!1,o=-1;for(;!a&&++o<B;){let e=z[o],n=e.isMultiMatch(i);n&&(r.push(new e(n,t)),a=!0)}if(!a)for(o=-1;++o<B;){let e=z[o],n=e.isSingleMatch(i);if(n){r.push(new e(n,t));break}}}return r})}var Ce=new Set([L.type,R.type]),we=class{constructor(e,{isCaseSensitive:t=k.isCaseSensitive,ignoreDiacritics:n=k.ignoreDiacritics,includeMatches:r=k.includeMatches,minMatchCharLength:i=k.minMatchCharLength,ignoreLocation:a=k.ignoreLocation,findAllMatches:o=k.findAllMatches,location:s=k.location,threshold:c=k.threshold,distance:l=k.distance}={}){this.query=null,this.options={isCaseSensitive:t,ignoreDiacritics:n,includeMatches:r,minMatchCharLength:i,findAllMatches:o,ignoreLocation:a,location:s,threshold:c,distance:l},e=t?e:e.toLowerCase(),e=n?N(e):e,this.pattern=e,this.query=Se(this.pattern,this.options)}static condition(e,t){return t.useExtendedSearch}searchIn(e){let t=this.query;if(!t)return{isMatch:!1,score:1};let{includeMatches:n,isCaseSensitive:r,ignoreDiacritics:i}=this.options;e=r?e:e.toLowerCase(),e=i?N(e):e;let a=0,o=[],s=0;for(let r=0,i=t.length;r<i;r+=1){let i=t[r];o.length=0,a=0;for(let t=0,r=i.length;t<r;t+=1){let r=i[t],{isMatch:c,indices:l,score:u}=r.search(e);if(c){if(a+=1,s+=u,n){let e=r.constructor.type;Ce.has(e)?o.push(...l):o.push(l)}}else{s=0,a=0,o.length=0;break}}if(a){let e={isMatch:!0,score:s/a};return n&&(e.indices=o),e}}return{isMatch:!1,score:1}}},V=[];function H(...e){V.push(...e)}function U(e,t){for(let n=0,r=V.length;n<r;n+=1){let r=V[n];if(r.condition(e,t))return new r(e,t)}return new P(e,t)}var W={AND:`$and`,OR:`$or`},G={PATH:`$path`,PATTERN:`$val`},K=e=>!!(e[W.AND]||e[W.OR]),Te=e=>!!e[G.PATH],q=e=>!l(e)&&g(e)&&!K(e),J=e=>({[W.AND]:Object.keys(e).map(t=>({[t]:e[t]}))});function Y(e,t,{auto:n=!0}={}){let r=e=>{let i=Object.keys(e),a=Te(e);if(!a&&i.length>1&&!K(e))return r(J(e));if(q(e)){let r=a?e[G.PATH]:i[0],o=a?e[G.PATTERN]:e[r];if(!p(o))throw Error(S(r));let s={keyId:O(r),pattern:o};return n&&(s.searcher=U(o,t)),s}let o={children:[],operator:i[0]};return i.forEach(t=>{let n=e[t];l(n)&&n.forEach(e=>{o.children.push(r(e))})}),o};return K(e)||(e=J(e)),r(e)}function X(e,{ignoreFieldNorm:t=k.ignoreFieldNorm}){let n=1;e.matches.forEach(({key:e,norm:r,score:i})=>{let a=e?e.weight:null;n*=(i===0&&a?2**-52:i)**+((a||1)*(t?1:r))}),e.score=n}function Ee(e,{ignoreFieldNorm:t=k.ignoreFieldNorm}){e.forEach(e=>{X(e,{ignoreFieldNorm:t})})}var De=class{constructor(e){this.limit=e,this.heap=[]}get size(){return this.heap.length}shouldInsert(e){return this.size<this.limit||e<this.heap[0].score}insert(e){this.size<this.limit?(this.heap.push(e),this._bubbleUp(this.size-1)):e.score<this.heap[0].score&&(this.heap[0]=e,this._sinkDown(0))}extractSorted(e){return this.heap.sort(e)}_bubbleUp(e){let t=this.heap;for(;e>0;){let n=e-1>>1;if(t[e].score<=t[n].score)break;let r=t[e];t[e]=t[n],t[n]=r,e=n}}_sinkDown(e){let t=this.heap,n=t.length,r=e;do{e=r;let i=2*e+1,a=2*e+2;if(i<n&&t[i].score>t[r].score&&(r=i),a<n&&t[a].score>t[r].score&&(r=a),r!==e){let n=t[e];t[e]=t[r],t[r]=n}}while(r!==e)}};function Oe(e,t){let n=e.matches;t.matches=[],v(n)&&n.forEach(e=>{if(!v(e.indices)||!e.indices.length)return;let{indices:n,value:r}=e,i={indices:n,value:r};e.key&&(i.key=e.key.src),e.idx>-1&&(i.refIndex=e.idx),t.matches.push(i)})}function ke(e,t){t.score=e.score}function Ae(e,t,{includeMatches:n=k.includeMatches,includeScore:r=k.includeScore}={}){let i=[];return n&&i.push(Oe),r&&i.push(ke),e.map(e=>{let{idx:n}=e,r={item:t[n],refIndex:n};return i.length&&i.forEach(t=>{t(e,r)}),r})}var Z=class{constructor(e,t={},n){this.options={...k,...t},this.options.useExtendedSearch,this._keyStore=new te(this.options.keys),this.setCollection(e,n),this._lastQuery=null,this._lastSearcher=null}_getSearcher(e){if(this._lastQuery===e)return this._lastSearcher;let t=U(e,this.options);return this._lastQuery=e,this._lastSearcher=t,t}setCollection(e,t){if(this._docs=e,t&&!(t instanceof A))throw Error(x);this._myIndex=t||j(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}add(e){v(e)&&(this._docs.push(e),this._myIndex.add(e))}remove(e=()=>!1){let t=[],n=[];for(let r=0,i=this._docs.length;r<i;r+=1)e(this._docs[r],r)&&(t.push(this._docs[r]),n.push(r));if(n.length){for(let e=n.length-1;e>=0;--e)this._docs.splice(n[e],1);this._myIndex.removeAll(n)}return t}removeAt(e){this._docs.splice(e,1),this._myIndex.removeAt(e)}getIndex(){return this._myIndex}search(e,{limit:t=-1}={}){let{includeMatches:n,includeScore:r,shouldSort:i,sortFn:a,ignoreFieldNorm:o}=this.options,s=m(t)&&t>0&&p(e),c;if(s){let n=new De(t);p(this._docs[0])?this._searchStringList(e,{heap:n,ignoreFieldNorm:o}):this._searchObjectList(e,{heap:n,ignoreFieldNorm:o}),c=n.extractSorted(a)}else c=p(e)?p(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e),Ee(c,{ignoreFieldNorm:o}),i&&c.sort(a),m(t)&&t>-1&&(c=c.slice(0,t));return Ae(c,this._docs,{includeMatches:n,includeScore:r})}_searchStringList(e,{heap:t,ignoreFieldNorm:n}={}){let r=this._getSearcher(e),{records:i}=this._myIndex,a=t?null:[];return i.forEach(({v:e,i,n:o})=>{if(!v(e))return;let{isMatch:s,score:c,indices:l}=r.searchIn(e);if(s){let r={item:e,idx:i,matches:[{score:c,value:e,norm:o,indices:l}]};t?(X(r,{ignoreFieldNorm:n}),t.shouldInsert(r.score)&&t.insert(r)):a.push(r)}}),a}_searchLogical(e){let t=Y(e,this.options),n=(e,t,r)=>{if(!e.children){let{keyId:n,searcher:i}=e,a=this._findMatches({key:this._keyStore.get(n),value:this._myIndex.getValueForItemAtKeyId(t,n),searcher:i});return a&&a.length?[{idx:r,item:t,matches:a}]:[]}let i=[];for(let a=0,o=e.children.length;a<o;a+=1){let o=e.children[a],s=n(o,t,r);if(s.length)i.push(...s);else if(e.operator===W.AND)return[]}return i},r=this._myIndex.records,i=new Map,a=[];return r.forEach(({$:e,i:r})=>{if(v(e)){let o=n(t,e,r);o.length&&(i.has(r)||(i.set(r,{idx:r,item:e,matches:[]}),a.push(i.get(r))),o.forEach(({matches:e})=>{i.get(r).matches.push(...e)}))}}),a}_searchObjectList(e,{heap:t,ignoreFieldNorm:n}={}){let r=this._getSearcher(e),{keys:i,records:a}=this._myIndex,o=t?null:[];return a.forEach(({$:e,i:a})=>{if(!v(e))return;let s=[];if(i.forEach((t,n)=>{s.push(...this._findMatches({key:t,value:e[n],searcher:r}))}),s.length){let r={idx:a,item:e,matches:s};t?(X(r,{ignoreFieldNorm:n}),t.shouldInsert(r.score)&&t.insert(r)):o.push(r)}}),o}_findMatches({key:e,value:t,searcher:n}){if(!v(t))return[];let r=[];if(l(t))t.forEach(({v:t,i,n:a})=>{if(!v(t))return;let{isMatch:o,score:s,indices:c}=n.searchIn(t);o&&r.push({score:s,key:e,value:t,idx:i,norm:a,indices:c})});else{let{v:i,n:a}=t,{isMatch:o,score:s,indices:c}=n.searchIn(i);o&&r.push({score:s,key:e,value:i,norm:a,indices:c})}return r}};Z.version=`7.2.0`,Z.createIndex=j,Z.parseIndex=le,Z.config=k,Z.parseQuery=Y,H(we),Z.use=function(...e){e.forEach(e=>H(e))};function Q(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}var $=class extends e{constructor(...e){super(...e),this.searchTerm=``,this.dataTask=new c(this,{task:async()=>{let e=await fetch(`/search-data.json`);if(!e.ok)throw Error(`HTTP ${e.status}`);let t=await e.json();return this.fuse=new Z(t,{keys:[`title`,`categories`,`excerpt`],shouldSort:!0,includeScore:!0}),t},args:()=>[]}),this.open=()=>{this.#e.value?.showModal()},this.close=()=>{this.#e.value?.close()}}#e=a();connectedCallback(){super.connectedCallback(),window.addEventListener(`keydown`,this.#t)}disconnectedCallback(){window.removeEventListener(`keydown`,this.#t)}get results(){return!this.searchTerm||!this.fuse||this.dataTask.status!==2?[]:this.fuse.search(this.searchTerm)}get hasResults(){return this.results.length>0}#t=e=>{let t=e.key===`k`&&e.getModifierState(`Meta`),n=e.key===`k`&&e.getModifierState(`Control`);(t||n)&&this.open()};#n=e=>{this.searchTerm=e.target.value};render(){return n`
|
|
2
|
+
<dialog part="qs-dialog" ${o(this.#e)}>
|
|
3
|
+
<div class="inner">
|
|
4
|
+
<div class="controls">
|
|
5
|
+
<input
|
|
6
|
+
autofocus
|
|
7
|
+
type="text"
|
|
8
|
+
placeholder="Search for a page"
|
|
9
|
+
part="qs-input"
|
|
10
|
+
value=${this.searchTerm}
|
|
11
|
+
@input=${this.#n}
|
|
12
|
+
/>
|
|
13
|
+
<button class="close" @click=${this.close}>Close</button>
|
|
14
|
+
</div>
|
|
15
|
+
<hr part="qs-divider" />
|
|
16
|
+
<div part="qs-results" class="results">
|
|
17
|
+
${this.dataTask.render({pending:()=>n`<div class="message">Loading search data...</div>`,error:e=>n`<div class="message error">
|
|
18
|
+
Search unavailable:
|
|
19
|
+
${e instanceof Error?e.message:`Unknown error`}
|
|
20
|
+
</div>`,complete:()=>this.hasResults?n`
|
|
21
|
+
<ul>
|
|
22
|
+
${s(this.results,({item:e})=>n`<li>
|
|
23
|
+
<a part="qs-result" class="result" href=${e.url}>
|
|
24
|
+
<div part="qs-title" class="title">
|
|
25
|
+
${e.title}
|
|
26
|
+
</div>
|
|
27
|
+
<div part="qs-excerpt" class="excerpt">
|
|
28
|
+
${e.excerpt}
|
|
29
|
+
</div>
|
|
30
|
+
<div part="qs-categories" class="categories">
|
|
31
|
+
${e.categories.map(e=>n`<span>${e}</span>`)}
|
|
32
|
+
</div>
|
|
33
|
+
</a>
|
|
34
|
+
</li>`)}
|
|
35
|
+
</ul>
|
|
36
|
+
`:n`<div class="message">
|
|
37
|
+
Enter a search term or select a category. Press escape to
|
|
38
|
+
return.
|
|
39
|
+
</div>`})}
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</dialog>
|
|
43
|
+
`}static{this.styles=t`
|
|
44
|
+
:host {
|
|
45
|
+
--gunmetal: #1b2f36;
|
|
46
|
+
--seasalt: #fafafa;
|
|
47
|
+
--carrot: #f79103;
|
|
48
|
+
--teal: #376170;
|
|
49
|
+
--raw-umber: #906b56;
|
|
50
|
+
--paynes-gray: #4d5963;
|
|
51
|
+
--shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
52
|
+
--gradient: linear-gradient(
|
|
53
|
+
135deg,
|
|
54
|
+
var(--paynes-gray) 0% 20%,
|
|
55
|
+
var(--carrot) 20% 40%,
|
|
56
|
+
var(--teal) 40% 60%,
|
|
57
|
+
var(--raw-umber) 60% 80%,
|
|
58
|
+
var(--gunmetal) 80% 100%
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
* {
|
|
63
|
+
box-sizing: border-box;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
*:focus-visible {
|
|
67
|
+
outline: 2px solid var(--raw-umber);
|
|
68
|
+
outline-offset: 1px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
dialog {
|
|
72
|
+
margin-top: 10vh;
|
|
73
|
+
height: auto;
|
|
74
|
+
width: 90vw;
|
|
75
|
+
max-width: 600px;
|
|
76
|
+
max-height: 80vh;
|
|
77
|
+
padding: 0;
|
|
78
|
+
border: 2px solid var(--gunmetal);
|
|
79
|
+
border-radius: 8px;
|
|
80
|
+
background: var(--seasalt);
|
|
81
|
+
color: var(--gunmetal);
|
|
82
|
+
box-shadow: var(--shadow);
|
|
83
|
+
overflow: hidden;
|
|
84
|
+
font-family: "Atkinson Hyperlegible Next", system-ui, sans-serif;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
dialog::backdrop {
|
|
88
|
+
backdrop-filter: blur(4px);
|
|
89
|
+
background: rgba(27, 47, 54, 0.1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.inner {
|
|
93
|
+
max-height: 100%;
|
|
94
|
+
padding: 1rem;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.controls {
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: 0.5rem;
|
|
101
|
+
margin-bottom: 1rem;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
input {
|
|
105
|
+
flex: 1;
|
|
106
|
+
padding: 0.75rem;
|
|
107
|
+
font: inherit;
|
|
108
|
+
font-size: 1rem;
|
|
109
|
+
border: 2px solid var(--teal);
|
|
110
|
+
border-radius: 8px;
|
|
111
|
+
background: var(--seasalt);
|
|
112
|
+
color: var(--gunmetal);
|
|
113
|
+
|
|
114
|
+
&:focus {
|
|
115
|
+
outline: none;
|
|
116
|
+
border-color: var(--carrot);
|
|
117
|
+
box-shadow: 0 0 0 2px rgba(247, 145, 3, 0.2);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
&::placeholder {
|
|
121
|
+
color: var(--paynes-gray);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.close {
|
|
126
|
+
display: inline-block;
|
|
127
|
+
padding: 0.75rem 1rem;
|
|
128
|
+
background: var(--gunmetal);
|
|
129
|
+
color: var(--seasalt);
|
|
130
|
+
border-radius: 8px;
|
|
131
|
+
box-shadow: var(--shadow);
|
|
132
|
+
border: none;
|
|
133
|
+
font: inherit;
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
|
|
136
|
+
&:hover {
|
|
137
|
+
background: var(--gradient);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
&:focus-visible {
|
|
141
|
+
outline: 2px solid var(--raw-umber);
|
|
142
|
+
outline-offset: 1px;
|
|
143
|
+
background: var(--gradient);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
hr {
|
|
148
|
+
width: 100%;
|
|
149
|
+
border: none;
|
|
150
|
+
height: 4px;
|
|
151
|
+
background: var(--gradient);
|
|
152
|
+
border-radius: 2px;
|
|
153
|
+
margin: 0 0 1rem 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.results {
|
|
157
|
+
max-height: 60vh;
|
|
158
|
+
overflow-y: auto;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.message {
|
|
162
|
+
padding: 2rem 1rem;
|
|
163
|
+
text-align: center;
|
|
164
|
+
color: var(--paynes-gray);
|
|
165
|
+
font-style: italic;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.message.error {
|
|
169
|
+
color: var(--raw-umber);
|
|
170
|
+
font-weight: bold;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
ul {
|
|
174
|
+
margin: 0;
|
|
175
|
+
padding: 0;
|
|
176
|
+
padding-top: 0.5rem;
|
|
177
|
+
list-style-type: none;
|
|
178
|
+
display: grid;
|
|
179
|
+
gap: 0.5rem;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.result {
|
|
183
|
+
display: block;
|
|
184
|
+
padding: 1rem;
|
|
185
|
+
color: var(--gunmetal);
|
|
186
|
+
text-decoration: none;
|
|
187
|
+
border: 2px solid transparent;
|
|
188
|
+
border-radius: 8px;
|
|
189
|
+
background: var(--seasalt);
|
|
190
|
+
transition: all 0.2s ease;
|
|
191
|
+
|
|
192
|
+
&:hover {
|
|
193
|
+
border-color: var(--teal);
|
|
194
|
+
transform: translateY(-1px);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
&:focus-visible {
|
|
198
|
+
outline: none;
|
|
199
|
+
border-color: var(--carrot);
|
|
200
|
+
box-shadow: 0 0 0 2px rgba(247, 145, 3, 0.2);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.title {
|
|
205
|
+
font-weight: bold;
|
|
206
|
+
font-size: 1.1rem;
|
|
207
|
+
margin-bottom: 0.25rem;
|
|
208
|
+
color: var(--gunmetal);
|
|
209
|
+
line-height: 1.2;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.excerpt {
|
|
213
|
+
font-size: 0.9rem;
|
|
214
|
+
color: var(--paynes-gray);
|
|
215
|
+
line-height: 1.4;
|
|
216
|
+
margin-bottom: 0.5rem;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.categories {
|
|
220
|
+
display: flex;
|
|
221
|
+
flex-wrap: wrap;
|
|
222
|
+
gap: 0.25rem;
|
|
223
|
+
font-size: 0.8rem;
|
|
224
|
+
text-transform: capitalize;
|
|
225
|
+
|
|
226
|
+
& span {
|
|
227
|
+
padding: 0.125rem 0.5rem;
|
|
228
|
+
background: var(--teal);
|
|
229
|
+
color: var(--seasalt);
|
|
230
|
+
border-radius: 4px;
|
|
231
|
+
font-weight: 500;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
& span:last-child::after {
|
|
235
|
+
content: none;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
/* Responsive adjustments */
|
|
241
|
+
@media (max-width: 600px) {
|
|
242
|
+
dialog {
|
|
243
|
+
width: 95vw;
|
|
244
|
+
margin-top: 5vh;
|
|
245
|
+
max-height: 85vh;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.inner {
|
|
249
|
+
padding: 0.75rem;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.controls {
|
|
253
|
+
flex-direction: column;
|
|
254
|
+
gap: 0.75rem;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.close {
|
|
258
|
+
width: 100%;
|
|
259
|
+
order: -1;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
input {
|
|
263
|
+
width: 100%;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
`}};Q([i()],$.prototype,`searchTerm`,void 0),$=Q([r(`quick-search`)],$);
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Vite + Lit + TS</title>
|
|
8
|
+
<script type="module" crossorigin src="/assets/index.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index.css">
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<quick-search>
|
|
13
|
+
<search-option
|
|
14
|
+
value="Web Components and You (part 1): The Shadow Dom"
|
|
15
|
+
excerpt="We look at why web components are a good solution now, and the very basics on how to make one."
|
|
16
|
+
categories="posts,web-components,cats"
|
|
17
|
+
url="/posts/2024/2/web-components-and-you-1/"
|
|
18
|
+
></search-option
|
|
19
|
+
><search-option
|
|
20
|
+
value="Web Components and You (part 2): Attributes and Reactivity"
|
|
21
|
+
excerpt="Let's take a look at web component attributes and how you can get your components to react to attribute changes!"
|
|
22
|
+
categories="posts,web-components,dogs"
|
|
23
|
+
url="/posts/2024/3/web-components-and-you-2-attributes/"
|
|
24
|
+
></search-option
|
|
25
|
+
><search-option
|
|
26
|
+
value="Web Components and You (part 3): Simplifying with Lit"
|
|
27
|
+
excerpt="It can be tedious to wire up reactivity in a web component ourselves. Let's see how easy it can be with Lit"
|
|
28
|
+
categories="posts,web-components"
|
|
29
|
+
url="/posts/2024/3/web-components-and-you-3/"
|
|
30
|
+
></search-option
|
|
31
|
+
><search-option
|
|
32
|
+
value="Web Components and You (part 4): Style"
|
|
33
|
+
excerpt="Let's visit how you would do CSS styles in a web component, and how Lit includes styles."
|
|
34
|
+
categories="posts,web-components"
|
|
35
|
+
url="/posts/2024/3/web-components-and-you-4/"
|
|
36
|
+
></search-option
|
|
37
|
+
><search-option
|
|
38
|
+
value="Web Components and You (part 5): Piercing the Shadow DOM"
|
|
39
|
+
excerpt="The Shadow DOM has scoped styles, which means that styles outside the shadow root don\'t affect it. But there are some exceptions! We will discuss the `:part()` psuedo-selector, css variables, declarative shadow DOM, and other ways the shadow DOM can be styled!"
|
|
40
|
+
categories="posts,web-components"
|
|
41
|
+
url="/posts/2024/3/web-components-and-you-5/"
|
|
42
|
+
></search-option
|
|
43
|
+
><search-option
|
|
44
|
+
value="Web Components and You (part 6): Slots and how to use them"
|
|
45
|
+
excerpt="Slots are a fantastic new feature that comes along with the Shadow DOM. You don\'t even need to make a custom element to use them. Let's look at how to use slots, name slots, and some of the lifecycles and features that come along with them."
|
|
46
|
+
categories="posts,web-components"
|
|
47
|
+
url="/posts/2024/4/web-components-and-you-6/"
|
|
48
|
+
></search-option
|
|
49
|
+
><search-option
|
|
50
|
+
value="Web Components and You (part 7): Let's talk about Shadow DOM mode"
|
|
51
|
+
excerpt="The Shadow DOM allows us a certain level of encapsulation, and there are two options for which mode you\'d like the Shadow DOM to be int: open or closed. We\'ll talk about the differences, the pros and cons, and ultimately whether it\'s worth it to close the Shadow DOM."
|
|
52
|
+
categories="posts,web-components"
|
|
53
|
+
url="/posts/2024/4/web-components-and-you-7/"
|
|
54
|
+
></search-option
|
|
55
|
+
><search-option
|
|
56
|
+
value="Web Components and You (part 8): Making a form element web component!"
|
|
57
|
+
excerpt="We can create form elements with our new web components, but we need to do a few new things: attach internals, handle focus delegation, and register the component as a bona fide form element with a value. It\'s pretty simple once you get into it- let's make a special text component as an example."
|
|
58
|
+
categories="posts,web-components"
|
|
59
|
+
url="/posts/2024/4/web-components-and-you-8/"
|
|
60
|
+
></search-option
|
|
61
|
+
><search-option
|
|
62
|
+
value="Web Components and You (part 9): Handling empty slots"
|
|
63
|
+
excerpt="Sometimes you want to check the contents of slots in the shadow DOM and conditionally do things based on what\'s in them. Can you do this with slots? Yes! It\'s a little strange though..."
|
|
64
|
+
categories="posts,web-components"
|
|
65
|
+
url="/posts/2024/8/web-components-and-you-9/"
|
|
66
|
+
></search-option
|
|
67
|
+
><search-option
|
|
68
|
+
value="Web Components and You (part 10): Provider patterns"
|
|
69
|
+
excerpt="Web components are by default pretty isolated. There are some nice patterns to start sharing state and actions among web components. This article explores the \'provider\' pattern"
|
|
70
|
+
categories="posts,web-components"
|
|
71
|
+
url="/posts/2024/8/web-components-and-you-10/"
|
|
72
|
+
></search-option>
|
|
73
|
+
</quick-search
|
|
74
|
+
>
|
|
75
|
+
<p>
|
|
76
|
+
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Quaerat dolor
|
|
77
|
+
magnam accusamus porro culpa sit, hic aliquam laborum voluptatum?
|
|
78
|
+
Temporibus molestiae aut quam ratione iste aspernatur quod vero libero
|
|
79
|
+
dolorem.
|
|
80
|
+
</p>
|
|
81
|
+
<p>
|
|
82
|
+
Voluptatibus saepe porro, ex id exercitationem odio fugit asperiores
|
|
83
|
+
dolorum dolor cupiditate aspernatur veritatis illum aperiam culpa sunt
|
|
84
|
+
quam sint ducimus harum quas impedit doloremque ea maxime recusandae modi?
|
|
85
|
+
Unde.
|
|
86
|
+
</p>
|
|
87
|
+
<p>
|
|
88
|
+
Aperiam cum ratione consequatur. Modi nisi rerum nulla debitis, odio
|
|
89
|
+
mollitia repudiandae aspernatur itaque autem impedit deleniti quam
|
|
90
|
+
provident omnis atque blanditiis! Expedita ex at dicta voluptates ut
|
|
91
|
+
delectus neque!
|
|
92
|
+
</p>
|
|
93
|
+
<p>
|
|
94
|
+
Nam, unde libero corporis possimus similique nesciunt labore doloribus
|
|
95
|
+
totam esse architecto quia officia delectus exercitationem ratione nulla
|
|
96
|
+
quos dolorem deserunt voluptatibus deleniti quo quas et repudiandae,
|
|
97
|
+
tempore eligendi. Nihil.
|
|
98
|
+
</p>
|
|
99
|
+
<p>
|
|
100
|
+
Consequuntur expedita ullam, magnam aliquid, natus recusandae hic libero
|
|
101
|
+
voluptatum labore odit velit eius debitis perferendis quia rem voluptatem,
|
|
102
|
+
accusamus autem non maiores. Neque consequuntur, voluptatum saepe minus
|
|
103
|
+
illo ipsa.
|
|
104
|
+
</p>
|
|
105
|
+
<p>
|
|
106
|
+
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Quaerat dolor
|
|
107
|
+
magnam accusamus porro culpa sit, hic aliquam laborum voluptatum?
|
|
108
|
+
Temporibus molestiae aut quam ratione iste aspernatur quod vero libero
|
|
109
|
+
dolorem.
|
|
110
|
+
</p>
|
|
111
|
+
<p>
|
|
112
|
+
Voluptatibus saepe porro, ex id exercitationem odio fugit asperiores
|
|
113
|
+
dolorum dolor cupiditate aspernatur veritatis illum aperiam culpa sunt
|
|
114
|
+
quam sint ducimus harum quas impedit doloremque ea maxime recusandae modi?
|
|
115
|
+
Unde.
|
|
116
|
+
</p>
|
|
117
|
+
<p>
|
|
118
|
+
Aperiam cum ratione consequatur. Modi nisi rerum nulla debitis, odio
|
|
119
|
+
mollitia repudiandae aspernatur itaque autem impedit deleniti quam
|
|
120
|
+
provident omnis atque blanditiis! Expedita ex at dicta voluptates ut
|
|
121
|
+
delectus neque!
|
|
122
|
+
</p>
|
|
123
|
+
<p>
|
|
124
|
+
Nam, unde libero corporis possimus similique nesciunt labore doloribus
|
|
125
|
+
totam esse architecto quia officia delectus exercitationem ratione nulla
|
|
126
|
+
quos dolorem deserunt voluptatibus deleniti quo quas et repudiandae,
|
|
127
|
+
tempore eligendi. Nihil.
|
|
128
|
+
</p>
|
|
129
|
+
<p>
|
|
130
|
+
Consequuntur expedita ullam, magnam aliquid, natus recusandae hic libero
|
|
131
|
+
voluptatum labore odit velit eius debitis perferendis quia rem voluptatem,
|
|
132
|
+
accusamus autem non maiores. Neque consequuntur, voluptatum saepe minus
|
|
133
|
+
illo ipsa.
|
|
134
|
+
</p>
|
|
135
|
+
</body>
|
|
136
|
+
</html>
|
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jschofield/quick-search",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/assets/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./dist/assets/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"description": "Site-wide search web component built with Lit and Fuse.js",
|
|
13
|
+
"author": "Jim Schofield",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/JimSchofield/jschof.dev",
|
|
18
|
+
"directory": "component/quick-search"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@lit/task": "^1.0.1",
|
|
22
|
+
"fuse.js": "^7.0.0"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"lit": "^3.0.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "^6.0.2",
|
|
29
|
+
"vite": "^8.0.3"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"dev": "vite",
|
|
33
|
+
"build": "tsc && vite build",
|
|
34
|
+
"preview": "vite preview"
|
|
35
|
+
}
|
|
36
|
+
}
|