@mhmo91/schmancy 0.9.23 → 0.9.24
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/custom-elements.json +22 -0
- package/dist/agent/schmancy.agent.js +219 -64
- package/dist/agent/schmancy.agent.js.map +1 -1
- package/dist/agent/schmancy.manifest.json +44 -0
- package/dist/handover/agent-runtime-followups.md +1 -1
- package/dist/handover/agent-runtime-v1.md +3 -3
- package/dist/handover/agent-runtime-v2-loopback.md +5 -5
- package/dist/typography.cjs +3 -3
- package/dist/typography.cjs.map +1 -1
- package/dist/typography.js +107 -10
- package/dist/typography.js.map +1 -1
- package/package.json +1 -1
- package/src/typography/typography.ts +94 -1
- package/types/src/typography/typography.d.ts +32 -0
|
@@ -6696,6 +6696,50 @@
|
|
|
6696
6696
|
],
|
|
6697
6697
|
"default": "'body'"
|
|
6698
6698
|
},
|
|
6699
|
+
{
|
|
6700
|
+
"name": "preset",
|
|
6701
|
+
"type": {
|
|
6702
|
+
"text": "TypographyPreset"
|
|
6703
|
+
},
|
|
6704
|
+
"values": [
|
|
6705
|
+
"display",
|
|
6706
|
+
"display-lg",
|
|
6707
|
+
"display-md",
|
|
6708
|
+
"display-sm",
|
|
6709
|
+
"heading-lg",
|
|
6710
|
+
"heading-md",
|
|
6711
|
+
"heading-sm",
|
|
6712
|
+
"title-lg",
|
|
6713
|
+
"title-md",
|
|
6714
|
+
"title-sm",
|
|
6715
|
+
"body-lg",
|
|
6716
|
+
"body-md",
|
|
6717
|
+
"body-sm",
|
|
6718
|
+
"label-lg",
|
|
6719
|
+
"label-md",
|
|
6720
|
+
"label-sm",
|
|
6721
|
+
"caption"
|
|
6722
|
+
],
|
|
6723
|
+
"description": "Shorthand for picking a (type, token) pair in one go. When set, derives `type` and `token` automatically — saves the two-decisions-per-text-node fatigue that hits when a single page has 50+ typography nodes."
|
|
6724
|
+
},
|
|
6725
|
+
{
|
|
6726
|
+
"name": "as",
|
|
6727
|
+
"type": {
|
|
6728
|
+
"text": "TypographyTag"
|
|
6729
|
+
},
|
|
6730
|
+
"values": [
|
|
6731
|
+
"h1",
|
|
6732
|
+
"h2",
|
|
6733
|
+
"h3",
|
|
6734
|
+
"h4",
|
|
6735
|
+
"h5",
|
|
6736
|
+
"h6",
|
|
6737
|
+
"p",
|
|
6738
|
+
"span",
|
|
6739
|
+
"div"
|
|
6740
|
+
],
|
|
6741
|
+
"description": "Render the slot wrapped in the requested semantic HTML element so screen readers expose the right role / heading level. Without `as`, the slot sits directly in the shadow root and the host is a generic element."
|
|
6742
|
+
},
|
|
6699
6743
|
{
|
|
6700
6744
|
"name": "token",
|
|
6701
6745
|
"type": {
|
|
@@ -203,7 +203,7 @@ The manifest already has everything needed; the package is just the JSON-RPC wra
|
|
|
203
203
|
|
|
204
204
|
**Problem.** `handover/agent-runtime-v1.md` had `<PENDING>` placeholders that we manually replaced with `0.9.13` after the first publish. Future handover docs will have the same issue.
|
|
205
205
|
|
|
206
|
-
**Fix.** A build step that substitutes `0.9.
|
|
206
|
+
**Fix.** A build step that substitutes `0.9.24` in `handover/**/*.md` against `package.json`'s `version` field on every build. `dist/handover/**/*.md` gets the rendered version; the source stays templated.
|
|
207
207
|
|
|
208
208
|
**Effort:** ~30 min (one sed step or a tiny script).
|
|
209
209
|
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
## The URLs you asked for
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
https://esm.sh/@mhmo91/schmancy/agent@0.9.
|
|
11
|
-
https://esm.sh/@mhmo91/schmancy/agent/manifest@0.9.
|
|
10
|
+
https://esm.sh/@mhmo91/schmancy/agent@0.9.24
|
|
11
|
+
https://esm.sh/@mhmo91/schmancy/agent/manifest@0.9.24
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
`0.9.13` is the first release containing `/agent`; every subsequent publish serves the same subpath. `npm view @mhmo91/schmancy version` always returns the current pin if you want to float forward.
|
|
@@ -20,7 +20,7 @@ One script tag. No bundler, no bare specifiers, no npm install.
|
|
|
20
20
|
```html
|
|
21
21
|
<!doctype html>
|
|
22
22
|
<script type="module">
|
|
23
|
-
import { $dialog, theme } from 'https://esm.sh/@mhmo91/schmancy/agent@0.9.
|
|
23
|
+
import { $dialog, theme } from 'https://esm.sh/@mhmo91/schmancy/agent@0.9.24';
|
|
24
24
|
</script>
|
|
25
25
|
<schmancy-theme root scheme="dark">
|
|
26
26
|
<schmancy-surface type="solid" fill="all">
|
|
@@ -12,7 +12,7 @@ Four separable PRs, each shippable on its own:
|
|
|
12
12
|
| # | Title | Branch | Impact on your probe |
|
|
13
13
|
|---|---|---|---|
|
|
14
14
|
| 2 | CI smoke-test gate | `feat/ci-gate-and-version-templating` | None user-facing. `window.schmancy.help()` regressions now fail-closed at publish time instead of shipping silently. |
|
|
15
|
-
| 9 | `0.9.
|
|
15
|
+
| 9 | `0.9.24` templating for handover docs | same branch as #2 | None user-facing. Future handover docs will have live esm.sh URLs instead of `<PENDING>` placeholders. |
|
|
16
16
|
| 3 | JSDoc backfill (46 components) | `feat/jsdoc-batch-{1,2,3}-*` | **This is what you'll notice.** Every form-control, container, and overlay/nav component now ships `@summary`, `@example`, and `@platform` tags in its manifest entry. `window.schmancy.help('schmancy-button')` returns a non-empty `summary`, a copy-pastable `examples[]`, and a `platformPrimitive` hint for graceful degradation. |
|
|
17
17
|
| 1 | Lazy vendor chunks | `feat/lazy-{typewriter,code-highlight,qr-scanner}` | Pages that don't render `<schmancy-code>`, `<schmancy-qr-scanner>`, or `<schmancy-typewriter>` no longer fetch `vendor-highlight`, `vendor-jsqr`, or the typewriter chunk on first paint. ~68 KB gzipped saved on cold starts for typical prototypes. |
|
|
18
18
|
|
|
@@ -21,18 +21,18 @@ The only one that changes the shape of `window.schmancy` is **#3**. The others a
|
|
|
21
21
|
## Pinned URLs (live once the PRs merge)
|
|
22
22
|
|
|
23
23
|
```
|
|
24
|
-
https://esm.sh/@mhmo91/schmancy/agent@0.9.
|
|
25
|
-
https://esm.sh/@mhmo91/schmancy/agent/manifest@0.9.
|
|
24
|
+
https://esm.sh/@mhmo91/schmancy/agent@0.9.24
|
|
25
|
+
https://esm.sh/@mhmo91/schmancy/agent/manifest@0.9.24
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
`0.9.
|
|
28
|
+
`0.9.24` is substituted at publish time — see [`agent-runtime-followups.md`](./agent-runtime-followups.md) #9. Until the PRs land, continue pinning `@0.9.14` (the last published version at time of writing).
|
|
29
29
|
|
|
30
30
|
## Minimum loop-back test
|
|
31
31
|
|
|
32
32
|
```html
|
|
33
33
|
<!doctype html>
|
|
34
34
|
<script type="module">
|
|
35
|
-
import 'https://esm.sh/@mhmo91/schmancy/agent@0.9.
|
|
35
|
+
import 'https://esm.sh/@mhmo91/schmancy/agent@0.9.24';
|
|
36
36
|
</script>
|
|
37
37
|
|
|
38
38
|
<schmancy-theme root scheme="dark">
|
package/dist/typography.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./chunk-CncqDLb2.cjs`);const e=require(`./tailwind.mixin-BHX99hgX.cjs`),t=require(`./decorate-F9CuyeHg.cjs`);let n=require(`rxjs`),r=require(`rxjs/operators`),i=require(`lit/decorators.js`),a=require(`lit`),o=require(`lit/directives/ref.js`);var s=class extends e.t(a.css`
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./chunk-CncqDLb2.cjs`);const e=require(`./tailwind.mixin-BHX99hgX.cjs`),t=require(`./decorate-F9CuyeHg.cjs`);let n=require(`rxjs`),r=require(`rxjs/operators`),i=require(`lit/decorators.js`),a=require(`lit`),o=require(`lit/directives/ref.js`),s=require(`lit/static-html.js`);var c={display:{type:`display`,token:`lg`},"display-lg":{type:`display`,token:`lg`},"display-md":{type:`display`,token:`md`},"display-sm":{type:`display`,token:`sm`},"heading-lg":{type:`headline`,token:`lg`},"heading-md":{type:`headline`,token:`md`},"heading-sm":{type:`headline`,token:`sm`},"title-lg":{type:`title`,token:`lg`},"title-md":{type:`title`,token:`md`},"title-sm":{type:`title`,token:`sm`},"body-lg":{type:`body`,token:`lg`},"body-md":{type:`body`,token:`md`},"body-sm":{type:`body`,token:`sm`},"label-lg":{type:`label`,token:`lg`},"label-md":{type:`label`,token:`md`},"label-sm":{type:`label`,token:`sm`},caption:{type:`label`,token:`sm`}},l={h1:s.literal`h1`,h2:s.literal`h2`,h3:s.literal`h3`,h4:s.literal`h4`,h5:s.literal`h5`,h6:s.literal`h6`,p:s.literal`p`,span:s.literal`span`,div:s.literal`div`},u=class extends e.t(a.css`
|
|
2
2
|
:host {
|
|
3
3
|
display: block;
|
|
4
4
|
font-family: inherit;
|
|
@@ -274,9 +274,9 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./ch
|
|
|
274
274
|
display: block;
|
|
275
275
|
opacity: 0.35;
|
|
276
276
|
}
|
|
277
|
-
`){constructor(...e){super(...e),this.type=`body`,this.token=`md`,this.editable=!1,this.value=``,this.placeholder=``,this._editRef=(0,o.createRef)()}static{this.shadowRootOptions={mode:`open`,delegatesFocus:!0}}selectAll(){let e=this._editRef.value;if(!e)return;e.focus();let t=window.getSelection();if(t&&e.textContent){let n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}}connectedCallback(){super.connectedCallback(),(0,n.fromEvent)(this,`focusout`).pipe((0,r.filter)(()=>this.editable),(0,r.tap)(()=>{let e=this._editRef.value;if(!e)return;let t=e.innerText.trim();t!==this.value&&this.dispatchEvent(new CustomEvent(`change`,{detail:{value:t},bubbles:!0,composed:!0})),t||(e.textContent=``)}),(0,r.takeUntil)(this.disconnecting)).subscribe(),(0,n.fromEvent)(this,`input`).pipe((0,r.filter)(()=>this.editable),(0,r.tap)(()=>{let e=this._editRef.value;e&&!e.innerText.trim()&&(e.textContent=``)}),(0,r.takeUntil)(this.disconnecting)).subscribe(),(0,n.fromEvent)(this,`keydown`).pipe((0,r.filter)(()=>this.editable),(0,r.filter)(e=>e.key===`Enter`),(0,r.tap)(e=>{e.preventDefault(),(this._editRef.value??this).blur()}),(0,r.takeUntil)(this.disconnecting)).subscribe()}updated(e){if(super.updated(e),e.has(`maxLines`)&&(this.classList.remove(`line-clamp-1`,`line-clamp-2`,`line-clamp-3`,`line-clamp-4`,`line-clamp-5`,`line-clamp-6`),this.maxLines&&this.classList.add(`line-clamp-${this.maxLines}`)),(e.has(`value`)||e.has(`editable`))&&this.editable){let e=this._editRef.value;e&&document.activeElement!==e&&(this.value?e.innerText=this.value:e.textContent=``)}}render(){
|
|
277
|
+
`){constructor(...e){super(...e),this.type=`body`,this.token=`md`,this.editable=!1,this.value=``,this.placeholder=``,this._editRef=(0,o.createRef)()}static{this.shadowRootOptions={mode:`open`,delegatesFocus:!0}}willUpdate(e){if(super.willUpdate?.(e),e.has(`preset`)&&this.preset&&c[this.preset]){let{type:e,token:t}=c[this.preset];this.type=e,this.token=t}}selectAll(){let e=this._editRef.value;if(!e)return;e.focus();let t=window.getSelection();if(t&&e.textContent){let n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}}connectedCallback(){super.connectedCallback(),(0,n.fromEvent)(this,`focusout`).pipe((0,r.filter)(()=>this.editable),(0,r.tap)(()=>{let e=this._editRef.value;if(!e)return;let t=e.innerText.trim();t!==this.value&&this.dispatchEvent(new CustomEvent(`change`,{detail:{value:t},bubbles:!0,composed:!0})),t||(e.textContent=``)}),(0,r.takeUntil)(this.disconnecting)).subscribe(),(0,n.fromEvent)(this,`input`).pipe((0,r.filter)(()=>this.editable),(0,r.tap)(()=>{let e=this._editRef.value;e&&!e.innerText.trim()&&(e.textContent=``)}),(0,r.takeUntil)(this.disconnecting)).subscribe(),(0,n.fromEvent)(this,`keydown`).pipe((0,r.filter)(()=>this.editable),(0,r.filter)(e=>e.key===`Enter`),(0,r.tap)(e=>{e.preventDefault(),(this._editRef.value??this).blur()}),(0,r.takeUntil)(this.disconnecting)).subscribe()}updated(e){if(super.updated(e),e.has(`maxLines`)&&(this.classList.remove(`line-clamp-1`,`line-clamp-2`,`line-clamp-3`,`line-clamp-4`,`line-clamp-5`,`line-clamp-6`),this.maxLines&&this.classList.add(`line-clamp-${this.maxLines}`)),(e.has(`value`)||e.has(`editable`))&&this.editable){let e=this._editRef.value;e&&document.activeElement!==e&&(this.value?e.innerText=this.value:e.textContent=``)}}render(){if(this.editable)return a.html`<div
|
|
278
278
|
${(0,o.ref)(this._editRef)}
|
|
279
279
|
class="edit"
|
|
280
280
|
contenteditable="true"
|
|
281
281
|
data-placeholder=${this.placeholder??``}
|
|
282
|
-
></div
|
|
282
|
+
></div>`;if(this.as&&l[this.as]){let e=l[this.as];return s.html`<${e}><slot></slot></${e}>`}return a.html`<slot></slot>`}};t.t([(0,i.property)({type:String,reflect:!0})],u.prototype,`type`,void 0),t.t([(0,i.property)({type:String,reflect:!0})],u.prototype,`preset`,void 0),t.t([(0,i.property)({type:String,reflect:!0})],u.prototype,`as`,void 0),t.t([(0,i.property)({type:String,reflect:!0})],u.prototype,`token`,void 0),t.t([(0,i.property)({type:String,reflect:!0})],u.prototype,`align`,void 0),t.t([(0,i.property)({type:String,reflect:!0})],u.prototype,`weight`,void 0),t.t([(0,i.property)({type:String,reflect:!0})],u.prototype,`transform`,void 0),t.t([(0,i.property)({type:Number})],u.prototype,`maxLines`,void 0),t.t([(0,i.property)({type:Boolean,reflect:!0})],u.prototype,`editable`,void 0),t.t([(0,i.property)({type:String})],u.prototype,`value`,void 0),t.t([(0,i.property)({type:String})],u.prototype,`placeholder`,void 0),u=t.t([(0,i.customElement)(`schmancy-typography`)],u),Object.defineProperty(exports,`SchmancyTypography`,{enumerable:!0,get:function(){return u}});
|
package/dist/typography.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typography.cjs","names":[],"sources":["../src/typography/typography.ts"],"sourcesContent":["import { TailwindElement } from '@mixins/tailwind.mixin'\nimport { css, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { fromEvent } from 'rxjs'\nimport { filter, tap, takeUntil } from 'rxjs/operators'\n\n// Material Design 3 typography - https://m3.material.io/styles/typography/type-scale-tokens\n\n/**\n * @element schmancy-typography\n * @slot - The text for the typography.\n */\n@customElement('schmancy-typography')\nexport class SchmancyTypography extends TailwindElement(css`\n\t:host {\n\t\tdisplay: block;\n\t\tfont-family: inherit;\n\t\thyphens: none;\n\t}\n\n\t/* Text alignment */\n\t:host([align='center']) {\n\t\ttext-align: center;\n\t}\n\n\t:host([align='left']) {\n\t\ttext-align: start;\n\t}\n\n\t:host([align='right']) {\n\t\ttext-align: right;\n\t}\n\n\t:host([align='justify']) {\n\t\ttext-align: justify;\n\t}\n\n\t/* Font weight */\n\t:host([weight='bold']) {\n\t\tfont-weight: 700;\n\t}\n\n\t:host([weight='medium']) {\n\t\tfont-weight: 500;\n\t}\n\n\t:host([weight='normal']) {\n\t\tfont-weight: 400;\n\t}\n\n\t/* Text transform */\n\t:host([transform='uppercase']) {\n\t\ttext-transform: uppercase;\n\t}\n\n\t:host([transform='lowercase']) {\n\t\ttext-transform: lowercase;\n\t}\n\n\t:host([transform='capitalize']) {\n\t\ttext-transform: capitalize;\n\t}\n\n\t:host([transform='normal']) {\n\t\ttext-transform: none;\n\t}\n\n\t/* Type-based weight defaults (when using Tailwind classes without token) */\n\t:host([type='display']),\n\t:host([type='headline']),\n\t:host([type='body']) {\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='label']),\n\t:host([type='subtitle']),\n\t:host([type='title']) {\n\t\tfont-weight: 500;\n\t}\n\n\t/* Display typography variants - Material Design 3 + Extended */\n\t:host([type='display'][token='xl']) {\n\t\tfont-size: 72px;\n\t\tline-height: 80px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='lg']) {\n\t\tfont-size: 57px;\n\t\tline-height: 64px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='md']) {\n\t\tfont-size: 45px;\n\t\tline-height: 52px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='sm']) {\n\t\tfont-size: 36px;\n\t\tline-height: 44px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='xs']) {\n\t\tfont-size: 28px;\n\t\tline-height: 36px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Headline typography variants - Material Design 3 + Extended */\n\t:host([type='headline'][token='xl']) {\n\t\tfont-size: 36px;\n\t\tline-height: 44px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='lg']) {\n\t\tfont-size: 32px;\n\t\tline-height: 40px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='md']) {\n\t\tfont-size: 28px;\n\t\tline-height: 36px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='sm']) {\n\t\tfont-size: 24px;\n\t\tline-height: 32px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='xs']) {\n\t\tfont-size: 20px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Title typography variants - Material Design 3 + Extended */\n\t:host([type='title'][token='xl']) {\n\t\tfont-size: 24px;\n\t\tline-height: 32px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='title'][token='lg']) {\n\t\tfont-size: 22px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='title'][token='md']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='title'][token='sm']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='title'][token='xs']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Subtitle typography variants - Extended from Material Design 3 */\n\t:host([type='subtitle'][token='xl']) {\n\t\tfont-size: 20px;\n\t\tline-height: 28px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='lg']) {\n\t\tfont-size: 18px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='md']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='sm']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='xs']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Body typography variants - Material Design 3 + Extended */\n\t:host([type='body'][token='xl']) {\n\t\tfont-size: 18px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='lg']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='md']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='sm']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='xs']) {\n\t\tfont-size: 10px;\n\t\tline-height: 14px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Label typography variants - Material Design 3 + Extended */\n\t:host([type='label'][token='xl']) {\n\t\tfont-size: 16px;\n\t\tline-height: 22px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='lg']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='md']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='sm']) {\n\t\tfont-size: 11px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='xs']) {\n\t\tfont-size: 10px;\n\t\tline-height: 14px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Note: Custom letter-spacing, font-size, and line-height should be applied via inline styles or Tailwind classes */\n\n\t:host([editable]) {\n\t\tcursor: text;\n\t\tborder-radius: 4px;\n\t\ttransition: background 150ms;\n\t\tmin-height: 1em;\n\t}\n\t/* Editable div lives in shadow DOM so light DOM (Lit markers) is untouched */\n\t.edit {\n\t\toutline: none;\n\t\tmin-height: 1em;\n\t\tfont: inherit;\n\t\tcolor: inherit;\n\t\tletter-spacing: inherit;\n\t\tline-height: inherit;\n\t}\n\t.edit:empty::before {\n\t\tcontent: attr(data-placeholder);\n\t\tpointer-events: none;\n\t\tdisplay: block;\n\t\topacity: 0.35;\n\t}\n`) {\n\tstatic shadowRootOptions: ShadowRootInit = {\n\t\tmode: 'open',\n\t\tdelegatesFocus: true,\n\t}\n\n\t/**\n\t * @attr type - The type of the typography.\n\t * @default 'body'\n\t * @type {'display' | 'headline' | 'title' | 'subtitle' | 'body' | 'label'}\n\t */\n\t@property({ type: String, reflect: true })\n\ttype: 'display' | 'headline' | 'title' | 'subtitle' | 'body' | 'label' = 'body'\n\n\t/**\n\t * @attr token - The size token.\n\t * @deprecated Prefer using Tailwind responsive text classes for better responsive design.\n\t * Set token=\"\" and use class=\"text-sm md:text-base lg:text-lg\" instead.\n\t * Example: <schmancy-typography type=\"display\" token=\"\" class=\"text-2xl sm:text-3xl md:text-4xl\">\n\t * @default 'md'\n\t * @type {'xs' | 'sm' | 'md' | 'lg' | 'xl' | ''}\n\t */\n\t@property({ type: String, reflect: true })\n\ttoken: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '' = 'md'\n\n\t/**\n\t * @attr\n\t * @default inherit\n\t * @type {'left' |'center' |'right'}\n\t */\n\t@property({ type: String, reflect: true })\n\talign: 'left' | 'center' | 'justify' | 'right' | undefined\n\n\t/**\n\t * @attr\n\t * @default inherit\n\t * @type {'normal' | 'medium' |'bold'}\n\t * @public\n\t */\n\t@property({ type: String, reflect: true })\n\tweight: 'normal' | 'medium' | 'bold' | undefined\n\t\n\t/**\n\t *\n\t * @attr\n\t * @default inherit\n\t * @type {'uppercase' |'lowercase' |'capitalize' |'normal'}\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) \n\ttransform: 'uppercase' | 'lowercase' | 'capitalize' | 'normal' | undefined\n\n\t@property({ type: Number })\n\tmaxLines: 1 | 2 | 3 | 4 | 5 | 6 | undefined\n\n\t/** When true, the element becomes contenteditable and dispatches 'change' events on blur/Enter */\n\t@property({ type: Boolean, reflect: true }) editable = false\n\t/** The text value when in editable mode. Set via property binding: .value=${...} */\n\t@property({ type: String }) value = ''\n\t/** Placeholder shown when editable and empty */\n\t@property({ type: String }) placeholder = ''\n\n\tprivate _editRef = createRef<HTMLDivElement>()\n\n\t/** Focus and select all text in editable mode */\n\tselectAll() {\n\t\tconst el = this._editRef.value\n\t\tif (!el) return\n\t\tel.focus()\n\t\tconst sel = window.getSelection()\n\t\tif (sel && el.textContent) {\n\t\t\tconst range = document.createRange()\n\t\t\trange.selectNodeContents(el)\n\t\t\tsel.removeAllRanges()\n\t\t\tsel.addRange(range)\n\t\t}\n\t}\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback()\n\n\t\tfromEvent<FocusEvent>(this, 'focusout').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\ttap(() => {\n\t\t\t\tconst el = this._editRef.value\n\t\t\t\tif (!el) return\n\t\t\t\tconst newValue = el.innerText.trim()\n\t\t\t\tif (newValue !== this.value) {\n\t\t\t\t\tthis.dispatchEvent(new CustomEvent('change', {\n\t\t\t\t\t\tdetail: { value: newValue },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t\t// Ensure truly empty so :empty CSS placeholder works\n\t\t\t\tif (!newValue) el.textContent = ''\n\t\t\t}),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\t// Clean stray <br> / whitespace nodes so :empty CSS matches\n\t\tfromEvent(this, 'input').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\ttap(() => {\n\t\t\t\tconst el = this._editRef.value\n\t\t\t\tif (el && !el.innerText.trim()) el.textContent = ''\n\t\t\t}),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tfromEvent<KeyboardEvent>(this, 'keydown').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\tfilter(e => e.key === 'Enter'),\n\t\t\ttap(e => { e.preventDefault(); (this._editRef.value ?? this).blur() }),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\t}\n\n\tprotected updated(changedProperties: Map<string, unknown>): void {\n\t\tsuper.updated(changedProperties)\n\t\tif (changedProperties.has('maxLines')) {\n\t\t\t// Remove all line-clamp classes\n\t\t\tthis.classList.remove('line-clamp-1', 'line-clamp-2', 'line-clamp-3', 'line-clamp-4', 'line-clamp-5', 'line-clamp-6')\n\t\t\t// Add the appropriate one\n\t\t\tif (this.maxLines) {\n\t\t\t\tthis.classList.add(`line-clamp-${this.maxLines}`)\n\t\t\t}\n\t\t}\n\t\tif ((changedProperties.has('value') || changedProperties.has('editable')) && this.editable) {\n\t\t\tconst el = this._editRef.value\n\t\t\tif (el && document.activeElement !== el) {\n\t\t\t\tif (this.value) {\n\t\t\t\t\tel.innerText = this.value\n\t\t\t\t} else {\n\t\t\t\t\tel.textContent = ''\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected render(): unknown {\n\t\tif (this.editable) {\n\t\t\treturn html`<div\n\t\t\t\t${ref(this._editRef)}\n\t\t\t\tclass=\"edit\"\n\t\t\t\tcontenteditable=\"true\"\n\t\t\t\tdata-placeholder=${this.placeholder ?? ''}\n\t\t\t></div>`\n\t\t}\n\t\treturn html`<slot></slot>`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-typography': SchmancyTypography\n\t}\n}"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"typography.cjs","names":[],"sources":["../src/typography/typography.ts"],"sourcesContent":["import { TailwindElement } from '@mixins/tailwind.mixin'\nimport { css, html, type PropertyValues } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { html as staticHtml, literal } from 'lit/static-html.js'\nimport { fromEvent } from 'rxjs'\nimport { filter, tap, takeUntil } from 'rxjs/operators'\n\n/**\n * Preset → (type, token) shorthand. Saves the two-decision-per-text-node\n * fatigue that 50+ typography nodes in a single page cause.\n */\nexport type TypographyPreset =\n\t| 'display' | 'display-lg' | 'display-md' | 'display-sm'\n\t| 'heading-lg' | 'heading-md' | 'heading-sm'\n\t| 'title-lg' | 'title-md' | 'title-sm'\n\t| 'body-lg' | 'body-md' | 'body-sm'\n\t| 'label-lg' | 'label-md' | 'label-sm'\n\t| 'caption'\n\nconst PRESET_MAP: Record<TypographyPreset, { type: string; token: string }> = {\n\t'display': { type: 'display', token: 'lg' },\n\t'display-lg': { type: 'display', token: 'lg' },\n\t'display-md': { type: 'display', token: 'md' },\n\t'display-sm': { type: 'display', token: 'sm' },\n\t'heading-lg': { type: 'headline', token: 'lg' },\n\t'heading-md': { type: 'headline', token: 'md' },\n\t'heading-sm': { type: 'headline', token: 'sm' },\n\t'title-lg': { type: 'title', token: 'lg' },\n\t'title-md': { type: 'title', token: 'md' },\n\t'title-sm': { type: 'title', token: 'sm' },\n\t'body-lg': { type: 'body', token: 'lg' },\n\t'body-md': { type: 'body', token: 'md' },\n\t'body-sm': { type: 'body', token: 'sm' },\n\t'label-lg': { type: 'label', token: 'lg' },\n\t'label-md': { type: 'label', token: 'md' },\n\t'label-sm': { type: 'label', token: 'sm' },\n\t'caption': { type: 'label', token: 'sm' },\n}\n\n/**\n * Allowed semantic tag names for the `as` prop. Closed enum so we can\n * use `literal` template parts safely with `lit/static-html`.\n */\nexport type TypographyTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span' | 'div'\n\nconst TAG_LITERALS: Record<TypographyTag, ReturnType<typeof literal>> = {\n\th1: literal`h1`,\n\th2: literal`h2`,\n\th3: literal`h3`,\n\th4: literal`h4`,\n\th5: literal`h5`,\n\th6: literal`h6`,\n\tp: literal`p`,\n\tspan: literal`span`,\n\tdiv: literal`div`,\n}\n\n// Material Design 3 typography - https://m3.material.io/styles/typography/type-scale-tokens\n\n/**\n * @element schmancy-typography\n * @slot - The text for the typography.\n */\n@customElement('schmancy-typography')\nexport class SchmancyTypography extends TailwindElement(css`\n\t:host {\n\t\tdisplay: block;\n\t\tfont-family: inherit;\n\t\thyphens: none;\n\t}\n\n\t/* Text alignment */\n\t:host([align='center']) {\n\t\ttext-align: center;\n\t}\n\n\t:host([align='left']) {\n\t\ttext-align: start;\n\t}\n\n\t:host([align='right']) {\n\t\ttext-align: right;\n\t}\n\n\t:host([align='justify']) {\n\t\ttext-align: justify;\n\t}\n\n\t/* Font weight */\n\t:host([weight='bold']) {\n\t\tfont-weight: 700;\n\t}\n\n\t:host([weight='medium']) {\n\t\tfont-weight: 500;\n\t}\n\n\t:host([weight='normal']) {\n\t\tfont-weight: 400;\n\t}\n\n\t/* Text transform */\n\t:host([transform='uppercase']) {\n\t\ttext-transform: uppercase;\n\t}\n\n\t:host([transform='lowercase']) {\n\t\ttext-transform: lowercase;\n\t}\n\n\t:host([transform='capitalize']) {\n\t\ttext-transform: capitalize;\n\t}\n\n\t:host([transform='normal']) {\n\t\ttext-transform: none;\n\t}\n\n\t/* Type-based weight defaults (when using Tailwind classes without token) */\n\t:host([type='display']),\n\t:host([type='headline']),\n\t:host([type='body']) {\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='label']),\n\t:host([type='subtitle']),\n\t:host([type='title']) {\n\t\tfont-weight: 500;\n\t}\n\n\t/* Display typography variants - Material Design 3 + Extended */\n\t:host([type='display'][token='xl']) {\n\t\tfont-size: 72px;\n\t\tline-height: 80px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='lg']) {\n\t\tfont-size: 57px;\n\t\tline-height: 64px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='md']) {\n\t\tfont-size: 45px;\n\t\tline-height: 52px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='sm']) {\n\t\tfont-size: 36px;\n\t\tline-height: 44px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='xs']) {\n\t\tfont-size: 28px;\n\t\tline-height: 36px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Headline typography variants - Material Design 3 + Extended */\n\t:host([type='headline'][token='xl']) {\n\t\tfont-size: 36px;\n\t\tline-height: 44px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='lg']) {\n\t\tfont-size: 32px;\n\t\tline-height: 40px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='md']) {\n\t\tfont-size: 28px;\n\t\tline-height: 36px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='sm']) {\n\t\tfont-size: 24px;\n\t\tline-height: 32px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='xs']) {\n\t\tfont-size: 20px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Title typography variants - Material Design 3 + Extended */\n\t:host([type='title'][token='xl']) {\n\t\tfont-size: 24px;\n\t\tline-height: 32px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='title'][token='lg']) {\n\t\tfont-size: 22px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='title'][token='md']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='title'][token='sm']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='title'][token='xs']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Subtitle typography variants - Extended from Material Design 3 */\n\t:host([type='subtitle'][token='xl']) {\n\t\tfont-size: 20px;\n\t\tline-height: 28px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='lg']) {\n\t\tfont-size: 18px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='md']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='sm']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='xs']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Body typography variants - Material Design 3 + Extended */\n\t:host([type='body'][token='xl']) {\n\t\tfont-size: 18px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='lg']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='md']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='sm']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='xs']) {\n\t\tfont-size: 10px;\n\t\tline-height: 14px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Label typography variants - Material Design 3 + Extended */\n\t:host([type='label'][token='xl']) {\n\t\tfont-size: 16px;\n\t\tline-height: 22px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='lg']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='md']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='sm']) {\n\t\tfont-size: 11px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='xs']) {\n\t\tfont-size: 10px;\n\t\tline-height: 14px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Note: Custom letter-spacing, font-size, and line-height should be applied via inline styles or Tailwind classes */\n\n\t:host([editable]) {\n\t\tcursor: text;\n\t\tborder-radius: 4px;\n\t\ttransition: background 150ms;\n\t\tmin-height: 1em;\n\t}\n\t/* Editable div lives in shadow DOM so light DOM (Lit markers) is untouched */\n\t.edit {\n\t\toutline: none;\n\t\tmin-height: 1em;\n\t\tfont: inherit;\n\t\tcolor: inherit;\n\t\tletter-spacing: inherit;\n\t\tline-height: inherit;\n\t}\n\t.edit:empty::before {\n\t\tcontent: attr(data-placeholder);\n\t\tpointer-events: none;\n\t\tdisplay: block;\n\t\topacity: 0.35;\n\t}\n`) {\n\tstatic shadowRootOptions: ShadowRootInit = {\n\t\tmode: 'open',\n\t\tdelegatesFocus: true,\n\t}\n\n\t/**\n\t * @attr type - The type of the typography.\n\t * @default 'body'\n\t * @type {'display' | 'headline' | 'title' | 'subtitle' | 'body' | 'label'}\n\t */\n\t@property({ type: String, reflect: true })\n\ttype: 'display' | 'headline' | 'title' | 'subtitle' | 'body' | 'label' = 'body'\n\n\t/**\n\t * Shorthand for picking a (type, token) pair in one go. When set, derives\n\t * `type` and `token` automatically — saves the two-decisions-per-text-node\n\t * fatigue that hits when a single page has 50+ typography nodes.\n\t *\n\t * @attr preset\n\t * @type {TypographyPreset}\n\t * @example <schmancy-typography preset=\"heading-md\">Title</schmancy-typography>\n\t */\n\t@property({ type: String, reflect: true })\n\tpreset?: TypographyPreset\n\n\t/**\n\t * Render the slot wrapped in the requested semantic HTML element so screen\n\t * readers expose the right role / heading level. Without `as`, the slot\n\t * sits directly in the shadow root and the host is a generic element.\n\t *\n\t * @attr as\n\t * @type {TypographyTag}\n\t * @example <schmancy-typography preset=\"heading-md\" as=\"h2\">Section</schmancy-typography>\n\t */\n\t@property({ type: String, reflect: true })\n\tas?: TypographyTag\n\n\t/**\n\t * @attr token - The size token.\n\t * @deprecated Prefer using Tailwind responsive text classes for better responsive design.\n\t * Set token=\"\" and use class=\"text-sm md:text-base lg:text-lg\" instead.\n\t * Example: <schmancy-typography type=\"display\" token=\"\" class=\"text-2xl sm:text-3xl md:text-4xl\">\n\t * @default 'md'\n\t * @type {'xs' | 'sm' | 'md' | 'lg' | 'xl' | ''}\n\t */\n\t@property({ type: String, reflect: true })\n\ttoken: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '' = 'md'\n\n\t/**\n\t * @attr\n\t * @default inherit\n\t * @type {'left' |'center' |'right'}\n\t */\n\t@property({ type: String, reflect: true })\n\talign: 'left' | 'center' | 'justify' | 'right' | undefined\n\n\t/**\n\t * @attr\n\t * @default inherit\n\t * @type {'normal' | 'medium' |'bold'}\n\t * @public\n\t */\n\t@property({ type: String, reflect: true })\n\tweight: 'normal' | 'medium' | 'bold' | undefined\n\t\n\t/**\n\t *\n\t * @attr\n\t * @default inherit\n\t * @type {'uppercase' |'lowercase' |'capitalize' |'normal'}\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) \n\ttransform: 'uppercase' | 'lowercase' | 'capitalize' | 'normal' | undefined\n\n\t@property({ type: Number })\n\tmaxLines: 1 | 2 | 3 | 4 | 5 | 6 | undefined\n\n\t/** When true, the element becomes contenteditable and dispatches 'change' events on blur/Enter */\n\t@property({ type: Boolean, reflect: true }) editable = false\n\t/** The text value when in editable mode. Set via property binding: .value=${...} */\n\t@property({ type: String }) value = ''\n\t/** Placeholder shown when editable and empty */\n\t@property({ type: String }) placeholder = ''\n\n\tprivate _editRef = createRef<HTMLDivElement>()\n\n\tprotected override willUpdate(changed: PropertyValues): void {\n\t\tsuper.willUpdate?.(changed)\n\t\t// `preset` shorthand expands to (type, token) so the existing CSS\n\t\t// selectors keep matching without duplicating the size scale.\n\t\tif (changed.has('preset') && this.preset && PRESET_MAP[this.preset]) {\n\t\t\tconst { type, token } = PRESET_MAP[this.preset]\n\t\t\tthis.type = type as typeof this.type\n\t\t\tthis.token = token as typeof this.token\n\t\t}\n\t}\n\n\t/** Focus and select all text in editable mode */\n\tselectAll() {\n\t\tconst el = this._editRef.value\n\t\tif (!el) return\n\t\tel.focus()\n\t\tconst sel = window.getSelection()\n\t\tif (sel && el.textContent) {\n\t\t\tconst range = document.createRange()\n\t\t\trange.selectNodeContents(el)\n\t\t\tsel.removeAllRanges()\n\t\t\tsel.addRange(range)\n\t\t}\n\t}\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback()\n\n\t\tfromEvent<FocusEvent>(this, 'focusout').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\ttap(() => {\n\t\t\t\tconst el = this._editRef.value\n\t\t\t\tif (!el) return\n\t\t\t\tconst newValue = el.innerText.trim()\n\t\t\t\tif (newValue !== this.value) {\n\t\t\t\t\tthis.dispatchEvent(new CustomEvent('change', {\n\t\t\t\t\t\tdetail: { value: newValue },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t\t// Ensure truly empty so :empty CSS placeholder works\n\t\t\t\tif (!newValue) el.textContent = ''\n\t\t\t}),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\t// Clean stray <br> / whitespace nodes so :empty CSS matches\n\t\tfromEvent(this, 'input').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\ttap(() => {\n\t\t\t\tconst el = this._editRef.value\n\t\t\t\tif (el && !el.innerText.trim()) el.textContent = ''\n\t\t\t}),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tfromEvent<KeyboardEvent>(this, 'keydown').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\tfilter(e => e.key === 'Enter'),\n\t\t\ttap(e => { e.preventDefault(); (this._editRef.value ?? this).blur() }),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\t}\n\n\tprotected updated(changedProperties: Map<string, unknown>): void {\n\t\tsuper.updated(changedProperties)\n\t\tif (changedProperties.has('maxLines')) {\n\t\t\t// Remove all line-clamp classes\n\t\t\tthis.classList.remove('line-clamp-1', 'line-clamp-2', 'line-clamp-3', 'line-clamp-4', 'line-clamp-5', 'line-clamp-6')\n\t\t\t// Add the appropriate one\n\t\t\tif (this.maxLines) {\n\t\t\t\tthis.classList.add(`line-clamp-${this.maxLines}`)\n\t\t\t}\n\t\t}\n\t\tif ((changedProperties.has('value') || changedProperties.has('editable')) && this.editable) {\n\t\t\tconst el = this._editRef.value\n\t\t\tif (el && document.activeElement !== el) {\n\t\t\t\tif (this.value) {\n\t\t\t\t\tel.innerText = this.value\n\t\t\t\t} else {\n\t\t\t\t\tel.textContent = ''\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected render(): unknown {\n\t\tif (this.editable) {\n\t\t\treturn html`<div\n\t\t\t\t${ref(this._editRef)}\n\t\t\t\tclass=\"edit\"\n\t\t\t\tcontenteditable=\"true\"\n\t\t\t\tdata-placeholder=${this.placeholder ?? ''}\n\t\t\t></div>`\n\t\t}\n\t\t// `as` wraps the slot in the requested semantic tag so heading levels\n\t\t// land in the accessibility tree. Without `as` the slot is bare and\n\t\t// the host element carries the visual styling only.\n\t\tif (this.as && TAG_LITERALS[this.as]) {\n\t\t\tconst tag = TAG_LITERALS[this.as]\n\t\t\treturn staticHtml`<${tag}><slot></slot></${tag}>`\n\t\t}\n\t\treturn html`<slot></slot>`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-typography': SchmancyTypography\n\t}\n}"],"mappings":"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"}
|
package/dist/typography.js
CHANGED
|
@@ -5,7 +5,87 @@ import { filter as r, takeUntil as i, tap as a } from "rxjs/operators";
|
|
|
5
5
|
import { customElement as o, property as s } from "lit/decorators.js";
|
|
6
6
|
import { css as c, html as l } from "lit";
|
|
7
7
|
import { createRef as u, ref as d } from "lit/directives/ref.js";
|
|
8
|
-
|
|
8
|
+
import { html as f, literal as p } from "lit/static-html.js";
|
|
9
|
+
var m = {
|
|
10
|
+
display: {
|
|
11
|
+
type: "display",
|
|
12
|
+
token: "lg"
|
|
13
|
+
},
|
|
14
|
+
"display-lg": {
|
|
15
|
+
type: "display",
|
|
16
|
+
token: "lg"
|
|
17
|
+
},
|
|
18
|
+
"display-md": {
|
|
19
|
+
type: "display",
|
|
20
|
+
token: "md"
|
|
21
|
+
},
|
|
22
|
+
"display-sm": {
|
|
23
|
+
type: "display",
|
|
24
|
+
token: "sm"
|
|
25
|
+
},
|
|
26
|
+
"heading-lg": {
|
|
27
|
+
type: "headline",
|
|
28
|
+
token: "lg"
|
|
29
|
+
},
|
|
30
|
+
"heading-md": {
|
|
31
|
+
type: "headline",
|
|
32
|
+
token: "md"
|
|
33
|
+
},
|
|
34
|
+
"heading-sm": {
|
|
35
|
+
type: "headline",
|
|
36
|
+
token: "sm"
|
|
37
|
+
},
|
|
38
|
+
"title-lg": {
|
|
39
|
+
type: "title",
|
|
40
|
+
token: "lg"
|
|
41
|
+
},
|
|
42
|
+
"title-md": {
|
|
43
|
+
type: "title",
|
|
44
|
+
token: "md"
|
|
45
|
+
},
|
|
46
|
+
"title-sm": {
|
|
47
|
+
type: "title",
|
|
48
|
+
token: "sm"
|
|
49
|
+
},
|
|
50
|
+
"body-lg": {
|
|
51
|
+
type: "body",
|
|
52
|
+
token: "lg"
|
|
53
|
+
},
|
|
54
|
+
"body-md": {
|
|
55
|
+
type: "body",
|
|
56
|
+
token: "md"
|
|
57
|
+
},
|
|
58
|
+
"body-sm": {
|
|
59
|
+
type: "body",
|
|
60
|
+
token: "sm"
|
|
61
|
+
},
|
|
62
|
+
"label-lg": {
|
|
63
|
+
type: "label",
|
|
64
|
+
token: "lg"
|
|
65
|
+
},
|
|
66
|
+
"label-md": {
|
|
67
|
+
type: "label",
|
|
68
|
+
token: "md"
|
|
69
|
+
},
|
|
70
|
+
"label-sm": {
|
|
71
|
+
type: "label",
|
|
72
|
+
token: "sm"
|
|
73
|
+
},
|
|
74
|
+
caption: {
|
|
75
|
+
type: "label",
|
|
76
|
+
token: "sm"
|
|
77
|
+
}
|
|
78
|
+
}, h = {
|
|
79
|
+
h1: p`h1`,
|
|
80
|
+
h2: p`h2`,
|
|
81
|
+
h3: p`h3`,
|
|
82
|
+
h4: p`h4`,
|
|
83
|
+
h5: p`h5`,
|
|
84
|
+
h6: p`h6`,
|
|
85
|
+
p: p`p`,
|
|
86
|
+
span: p`span`,
|
|
87
|
+
div: p`div`
|
|
88
|
+
}, g = class extends e(c`
|
|
9
89
|
:host {
|
|
10
90
|
display: block;
|
|
11
91
|
font-family: inherit;
|
|
@@ -291,6 +371,12 @@ var f = class extends e(c`
|
|
|
291
371
|
delegatesFocus: !0
|
|
292
372
|
};
|
|
293
373
|
}
|
|
374
|
+
willUpdate(e) {
|
|
375
|
+
if (super.willUpdate?.(e), e.has("preset") && this.preset && m[this.preset]) {
|
|
376
|
+
let { type: e, token: t } = m[this.preset];
|
|
377
|
+
this.type = e, this.token = t;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
294
380
|
selectAll() {
|
|
295
381
|
let e = this._editRef.value;
|
|
296
382
|
if (!e) return;
|
|
@@ -325,31 +411,42 @@ var f = class extends e(c`
|
|
|
325
411
|
}
|
|
326
412
|
}
|
|
327
413
|
render() {
|
|
328
|
-
|
|
414
|
+
if (this.editable) return l`<div
|
|
329
415
|
${d(this._editRef)}
|
|
330
416
|
class="edit"
|
|
331
417
|
contenteditable="true"
|
|
332
418
|
data-placeholder=${this.placeholder ?? ""}
|
|
333
|
-
></div
|
|
419
|
+
></div>`;
|
|
420
|
+
if (this.as && h[this.as]) {
|
|
421
|
+
let e = h[this.as];
|
|
422
|
+
return f`<${e}><slot></slot></${e}>`;
|
|
423
|
+
}
|
|
424
|
+
return l`<slot></slot>`;
|
|
334
425
|
}
|
|
335
426
|
};
|
|
336
427
|
t([s({
|
|
337
428
|
type: String,
|
|
338
429
|
reflect: !0
|
|
339
|
-
})],
|
|
430
|
+
})], g.prototype, "type", void 0), t([s({
|
|
431
|
+
type: String,
|
|
432
|
+
reflect: !0
|
|
433
|
+
})], g.prototype, "preset", void 0), t([s({
|
|
434
|
+
type: String,
|
|
435
|
+
reflect: !0
|
|
436
|
+
})], g.prototype, "as", void 0), t([s({
|
|
340
437
|
type: String,
|
|
341
438
|
reflect: !0
|
|
342
|
-
})],
|
|
439
|
+
})], g.prototype, "token", void 0), t([s({
|
|
343
440
|
type: String,
|
|
344
441
|
reflect: !0
|
|
345
|
-
})],
|
|
442
|
+
})], g.prototype, "align", void 0), t([s({
|
|
346
443
|
type: String,
|
|
347
444
|
reflect: !0
|
|
348
|
-
})],
|
|
445
|
+
})], g.prototype, "weight", void 0), t([s({
|
|
349
446
|
type: String,
|
|
350
447
|
reflect: !0
|
|
351
|
-
})],
|
|
448
|
+
})], g.prototype, "transform", void 0), t([s({ type: Number })], g.prototype, "maxLines", void 0), t([s({
|
|
352
449
|
type: Boolean,
|
|
353
450
|
reflect: !0
|
|
354
|
-
})],
|
|
355
|
-
export {
|
|
451
|
+
})], g.prototype, "editable", void 0), t([s({ type: String })], g.prototype, "value", void 0), t([s({ type: String })], g.prototype, "placeholder", void 0), g = t([o("schmancy-typography")], g);
|
|
452
|
+
export { g as SchmancyTypography };
|
package/dist/typography.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typography.js","names":[],"sources":["../src/typography/typography.ts"],"sourcesContent":["import { TailwindElement } from '@mixins/tailwind.mixin'\nimport { css, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { fromEvent } from 'rxjs'\nimport { filter, tap, takeUntil } from 'rxjs/operators'\n\n// Material Design 3 typography - https://m3.material.io/styles/typography/type-scale-tokens\n\n/**\n * @element schmancy-typography\n * @slot - The text for the typography.\n */\n@customElement('schmancy-typography')\nexport class SchmancyTypography extends TailwindElement(css`\n\t:host {\n\t\tdisplay: block;\n\t\tfont-family: inherit;\n\t\thyphens: none;\n\t}\n\n\t/* Text alignment */\n\t:host([align='center']) {\n\t\ttext-align: center;\n\t}\n\n\t:host([align='left']) {\n\t\ttext-align: start;\n\t}\n\n\t:host([align='right']) {\n\t\ttext-align: right;\n\t}\n\n\t:host([align='justify']) {\n\t\ttext-align: justify;\n\t}\n\n\t/* Font weight */\n\t:host([weight='bold']) {\n\t\tfont-weight: 700;\n\t}\n\n\t:host([weight='medium']) {\n\t\tfont-weight: 500;\n\t}\n\n\t:host([weight='normal']) {\n\t\tfont-weight: 400;\n\t}\n\n\t/* Text transform */\n\t:host([transform='uppercase']) {\n\t\ttext-transform: uppercase;\n\t}\n\n\t:host([transform='lowercase']) {\n\t\ttext-transform: lowercase;\n\t}\n\n\t:host([transform='capitalize']) {\n\t\ttext-transform: capitalize;\n\t}\n\n\t:host([transform='normal']) {\n\t\ttext-transform: none;\n\t}\n\n\t/* Type-based weight defaults (when using Tailwind classes without token) */\n\t:host([type='display']),\n\t:host([type='headline']),\n\t:host([type='body']) {\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='label']),\n\t:host([type='subtitle']),\n\t:host([type='title']) {\n\t\tfont-weight: 500;\n\t}\n\n\t/* Display typography variants - Material Design 3 + Extended */\n\t:host([type='display'][token='xl']) {\n\t\tfont-size: 72px;\n\t\tline-height: 80px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='lg']) {\n\t\tfont-size: 57px;\n\t\tline-height: 64px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='md']) {\n\t\tfont-size: 45px;\n\t\tline-height: 52px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='sm']) {\n\t\tfont-size: 36px;\n\t\tline-height: 44px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='xs']) {\n\t\tfont-size: 28px;\n\t\tline-height: 36px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Headline typography variants - Material Design 3 + Extended */\n\t:host([type='headline'][token='xl']) {\n\t\tfont-size: 36px;\n\t\tline-height: 44px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='lg']) {\n\t\tfont-size: 32px;\n\t\tline-height: 40px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='md']) {\n\t\tfont-size: 28px;\n\t\tline-height: 36px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='sm']) {\n\t\tfont-size: 24px;\n\t\tline-height: 32px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='xs']) {\n\t\tfont-size: 20px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Title typography variants - Material Design 3 + Extended */\n\t:host([type='title'][token='xl']) {\n\t\tfont-size: 24px;\n\t\tline-height: 32px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='title'][token='lg']) {\n\t\tfont-size: 22px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='title'][token='md']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='title'][token='sm']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='title'][token='xs']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Subtitle typography variants - Extended from Material Design 3 */\n\t:host([type='subtitle'][token='xl']) {\n\t\tfont-size: 20px;\n\t\tline-height: 28px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='lg']) {\n\t\tfont-size: 18px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='md']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='sm']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='xs']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Body typography variants - Material Design 3 + Extended */\n\t:host([type='body'][token='xl']) {\n\t\tfont-size: 18px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='lg']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='md']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='sm']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='xs']) {\n\t\tfont-size: 10px;\n\t\tline-height: 14px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Label typography variants - Material Design 3 + Extended */\n\t:host([type='label'][token='xl']) {\n\t\tfont-size: 16px;\n\t\tline-height: 22px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='lg']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='md']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='sm']) {\n\t\tfont-size: 11px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='xs']) {\n\t\tfont-size: 10px;\n\t\tline-height: 14px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Note: Custom letter-spacing, font-size, and line-height should be applied via inline styles or Tailwind classes */\n\n\t:host([editable]) {\n\t\tcursor: text;\n\t\tborder-radius: 4px;\n\t\ttransition: background 150ms;\n\t\tmin-height: 1em;\n\t}\n\t/* Editable div lives in shadow DOM so light DOM (Lit markers) is untouched */\n\t.edit {\n\t\toutline: none;\n\t\tmin-height: 1em;\n\t\tfont: inherit;\n\t\tcolor: inherit;\n\t\tletter-spacing: inherit;\n\t\tline-height: inherit;\n\t}\n\t.edit:empty::before {\n\t\tcontent: attr(data-placeholder);\n\t\tpointer-events: none;\n\t\tdisplay: block;\n\t\topacity: 0.35;\n\t}\n`) {\n\tstatic shadowRootOptions: ShadowRootInit = {\n\t\tmode: 'open',\n\t\tdelegatesFocus: true,\n\t}\n\n\t/**\n\t * @attr type - The type of the typography.\n\t * @default 'body'\n\t * @type {'display' | 'headline' | 'title' | 'subtitle' | 'body' | 'label'}\n\t */\n\t@property({ type: String, reflect: true })\n\ttype: 'display' | 'headline' | 'title' | 'subtitle' | 'body' | 'label' = 'body'\n\n\t/**\n\t * @attr token - The size token.\n\t * @deprecated Prefer using Tailwind responsive text classes for better responsive design.\n\t * Set token=\"\" and use class=\"text-sm md:text-base lg:text-lg\" instead.\n\t * Example: <schmancy-typography type=\"display\" token=\"\" class=\"text-2xl sm:text-3xl md:text-4xl\">\n\t * @default 'md'\n\t * @type {'xs' | 'sm' | 'md' | 'lg' | 'xl' | ''}\n\t */\n\t@property({ type: String, reflect: true })\n\ttoken: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '' = 'md'\n\n\t/**\n\t * @attr\n\t * @default inherit\n\t * @type {'left' |'center' |'right'}\n\t */\n\t@property({ type: String, reflect: true })\n\talign: 'left' | 'center' | 'justify' | 'right' | undefined\n\n\t/**\n\t * @attr\n\t * @default inherit\n\t * @type {'normal' | 'medium' |'bold'}\n\t * @public\n\t */\n\t@property({ type: String, reflect: true })\n\tweight: 'normal' | 'medium' | 'bold' | undefined\n\t\n\t/**\n\t *\n\t * @attr\n\t * @default inherit\n\t * @type {'uppercase' |'lowercase' |'capitalize' |'normal'}\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) \n\ttransform: 'uppercase' | 'lowercase' | 'capitalize' | 'normal' | undefined\n\n\t@property({ type: Number })\n\tmaxLines: 1 | 2 | 3 | 4 | 5 | 6 | undefined\n\n\t/** When true, the element becomes contenteditable and dispatches 'change' events on blur/Enter */\n\t@property({ type: Boolean, reflect: true }) editable = false\n\t/** The text value when in editable mode. Set via property binding: .value=${...} */\n\t@property({ type: String }) value = ''\n\t/** Placeholder shown when editable and empty */\n\t@property({ type: String }) placeholder = ''\n\n\tprivate _editRef = createRef<HTMLDivElement>()\n\n\t/** Focus and select all text in editable mode */\n\tselectAll() {\n\t\tconst el = this._editRef.value\n\t\tif (!el) return\n\t\tel.focus()\n\t\tconst sel = window.getSelection()\n\t\tif (sel && el.textContent) {\n\t\t\tconst range = document.createRange()\n\t\t\trange.selectNodeContents(el)\n\t\t\tsel.removeAllRanges()\n\t\t\tsel.addRange(range)\n\t\t}\n\t}\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback()\n\n\t\tfromEvent<FocusEvent>(this, 'focusout').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\ttap(() => {\n\t\t\t\tconst el = this._editRef.value\n\t\t\t\tif (!el) return\n\t\t\t\tconst newValue = el.innerText.trim()\n\t\t\t\tif (newValue !== this.value) {\n\t\t\t\t\tthis.dispatchEvent(new CustomEvent('change', {\n\t\t\t\t\t\tdetail: { value: newValue },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t\t// Ensure truly empty so :empty CSS placeholder works\n\t\t\t\tif (!newValue) el.textContent = ''\n\t\t\t}),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\t// Clean stray <br> / whitespace nodes so :empty CSS matches\n\t\tfromEvent(this, 'input').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\ttap(() => {\n\t\t\t\tconst el = this._editRef.value\n\t\t\t\tif (el && !el.innerText.trim()) el.textContent = ''\n\t\t\t}),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tfromEvent<KeyboardEvent>(this, 'keydown').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\tfilter(e => e.key === 'Enter'),\n\t\t\ttap(e => { e.preventDefault(); (this._editRef.value ?? this).blur() }),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\t}\n\n\tprotected updated(changedProperties: Map<string, unknown>): void {\n\t\tsuper.updated(changedProperties)\n\t\tif (changedProperties.has('maxLines')) {\n\t\t\t// Remove all line-clamp classes\n\t\t\tthis.classList.remove('line-clamp-1', 'line-clamp-2', 'line-clamp-3', 'line-clamp-4', 'line-clamp-5', 'line-clamp-6')\n\t\t\t// Add the appropriate one\n\t\t\tif (this.maxLines) {\n\t\t\t\tthis.classList.add(`line-clamp-${this.maxLines}`)\n\t\t\t}\n\t\t}\n\t\tif ((changedProperties.has('value') || changedProperties.has('editable')) && this.editable) {\n\t\t\tconst el = this._editRef.value\n\t\t\tif (el && document.activeElement !== el) {\n\t\t\t\tif (this.value) {\n\t\t\t\t\tel.innerText = this.value\n\t\t\t\t} else {\n\t\t\t\t\tel.textContent = ''\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected render(): unknown {\n\t\tif (this.editable) {\n\t\t\treturn html`<div\n\t\t\t\t${ref(this._editRef)}\n\t\t\t\tclass=\"edit\"\n\t\t\t\tcontenteditable=\"true\"\n\t\t\t\tdata-placeholder=${this.placeholder ?? ''}\n\t\t\t></div>`\n\t\t}\n\t\treturn html`<slot></slot>`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-typography': SchmancyTypography\n\t}\n}"],"mappings":";;;;;;;AAcO,IAAA,IAAA,cAAiC,EAAgB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAgSe,QAAA,KAAA,QAW1B,MAAA,KAAA,WAAA,CAiCQ,GAAA,KAAA,QAEnB,IAAA,KAAA,cAEM,IAAA,KAAA,WAEvB,GAAA;;CAAA;AAAA,OAAA,oBA7DwB;GAC1C,MAAM;GACN,gBAAA,CAAgB;GAAA;;CA8DjB,YAAA;EACC,IAAM,IAAK,KAAK,SAAS;AACzB,MAAA,CAAK,EAAI;AACT,IAAG,OAAA;EACH,IAAM,IAAM,OAAO,cAAA;AACnB,MAAI,KAAO,EAAG,aAAa;GAC1B,IAAM,IAAQ,SAAS,aAAA;AACvB,KAAM,mBAAmB,EAAA,EACzB,EAAI,iBAAA,EACJ,EAAI,SAAS,EAAA;;;CAIf,oBAAA;AACC,QAAM,mBAAA,EAEN,EAAsB,MAAM,WAAA,CAAY,KACvC,QAAa,KAAK,SAAA,EAClB,QAAA;GACC,IAAM,IAAK,KAAK,SAAS;AACzB,OAAA,CAAK,EAAI;GACT,IAAM,IAAW,EAAG,UAAU,MAAA;AAC1B,SAAa,KAAK,SACrB,KAAK,cAAc,IAAI,YAAY,UAAU;IAC5C,QAAQ,EAAE,OAAO,GAAA;IACjB,SAAA,CAAS;IACT,UAAA,CAAU;IAAA,CAAA,CAAA,EAIP,MAAU,EAAG,cAAc;IAAA,EAEjC,EAAU,KAAK,cAAA,CAAA,CACd,WAAA,EAGF,EAAU,MAAM,QAAA,CAAS,KACxB,QAAa,KAAK,SAAA,EAClB,QAAA;GACC,IAAM,IAAK,KAAK,SAAS;AACrB,QAAA,CAAO,EAAG,UAAU,MAAA,KAAQ,EAAG,cAAc;IAAA,EAElD,EAAU,KAAK,cAAA,CAAA,CACd,WAAA,EAEF,EAAyB,MAAM,UAAA,CAAW,KACzC,QAAa,KAAK,SAAA,EAClB,GAAO,MAAK,EAAE,QAAQ,QAAR,EACd,GAAI,MAAA;AAAO,KAAE,gBAAA,GAAmB,KAAK,SAAS,SAAS,MAAM,MAAA;IAAA,EAC7D,EAAU,KAAK,cAAA,CAAA,CACd,WAAA;;CAGH,QAAkB,GAAA;AAUjB,MATA,MAAM,QAAQ,EAAA,EACV,EAAkB,IAAI,WAAA,KAEzB,KAAK,UAAU,OAAO,gBAAgB,gBAAgB,gBAAgB,gBAAgB,gBAAgB,eAAA,EAElG,KAAK,YACR,KAAK,UAAU,IAAI,cAAc,KAAK,WAAA,IAGnC,EAAkB,IAAI,QAAA,IAAY,EAAkB,IAAI,WAAA,KAAgB,KAAK,UAAU;GAC3F,IAAM,IAAK,KAAK,SAAS;AACrB,QAAM,SAAS,kBAAkB,MAChC,KAAK,QACR,EAAG,YAAY,KAAK,QAEpB,EAAG,cAAc;;;CAMrB,SAAA;AACC,SAAI,KAAK,WACD,CAAI;MACR,EAAI,KAAK,SAAA,CAAA;;;uBAGQ,KAAK,eAAe,GAAA;cAGlC,CAAI;;;AAAA,EAAA,CA1IX,EAAS;CAAE,MAAM;CAAQ,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,QAAA,KAAA,EAAA,EAAA,EAAA,CAWzC,EAAS;CAAE,MAAM;CAAQ,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,EAAA,CAQzC,EAAS;CAAE,MAAM;CAAQ,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,EAAA,CASzC,EAAS;CAAE,MAAM;CAAQ,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,UAAA,KAAA,EAAA,EAAA,EAAA,CAUzC,EAAS;CAAE,MAAM;CAAQ,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,aAAA,KAAA,EAAA,EAAA,EAAA,CAGzC,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAI1B,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAE1C,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,EAAA,CAE1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,eAAA,KAAA,EAAA,EAAA,IAAA,EAAA,CAjV3B,EAAc,sBAAA,CAAA,EAAsB,EAAA;AAAA,SAAA,KAAA"}
|
|
1
|
+
{"version":3,"file":"typography.js","names":[],"sources":["../src/typography/typography.ts"],"sourcesContent":["import { TailwindElement } from '@mixins/tailwind.mixin'\nimport { css, html, type PropertyValues } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { html as staticHtml, literal } from 'lit/static-html.js'\nimport { fromEvent } from 'rxjs'\nimport { filter, tap, takeUntil } from 'rxjs/operators'\n\n/**\n * Preset → (type, token) shorthand. Saves the two-decision-per-text-node\n * fatigue that 50+ typography nodes in a single page cause.\n */\nexport type TypographyPreset =\n\t| 'display' | 'display-lg' | 'display-md' | 'display-sm'\n\t| 'heading-lg' | 'heading-md' | 'heading-sm'\n\t| 'title-lg' | 'title-md' | 'title-sm'\n\t| 'body-lg' | 'body-md' | 'body-sm'\n\t| 'label-lg' | 'label-md' | 'label-sm'\n\t| 'caption'\n\nconst PRESET_MAP: Record<TypographyPreset, { type: string; token: string }> = {\n\t'display': { type: 'display', token: 'lg' },\n\t'display-lg': { type: 'display', token: 'lg' },\n\t'display-md': { type: 'display', token: 'md' },\n\t'display-sm': { type: 'display', token: 'sm' },\n\t'heading-lg': { type: 'headline', token: 'lg' },\n\t'heading-md': { type: 'headline', token: 'md' },\n\t'heading-sm': { type: 'headline', token: 'sm' },\n\t'title-lg': { type: 'title', token: 'lg' },\n\t'title-md': { type: 'title', token: 'md' },\n\t'title-sm': { type: 'title', token: 'sm' },\n\t'body-lg': { type: 'body', token: 'lg' },\n\t'body-md': { type: 'body', token: 'md' },\n\t'body-sm': { type: 'body', token: 'sm' },\n\t'label-lg': { type: 'label', token: 'lg' },\n\t'label-md': { type: 'label', token: 'md' },\n\t'label-sm': { type: 'label', token: 'sm' },\n\t'caption': { type: 'label', token: 'sm' },\n}\n\n/**\n * Allowed semantic tag names for the `as` prop. Closed enum so we can\n * use `literal` template parts safely with `lit/static-html`.\n */\nexport type TypographyTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span' | 'div'\n\nconst TAG_LITERALS: Record<TypographyTag, ReturnType<typeof literal>> = {\n\th1: literal`h1`,\n\th2: literal`h2`,\n\th3: literal`h3`,\n\th4: literal`h4`,\n\th5: literal`h5`,\n\th6: literal`h6`,\n\tp: literal`p`,\n\tspan: literal`span`,\n\tdiv: literal`div`,\n}\n\n// Material Design 3 typography - https://m3.material.io/styles/typography/type-scale-tokens\n\n/**\n * @element schmancy-typography\n * @slot - The text for the typography.\n */\n@customElement('schmancy-typography')\nexport class SchmancyTypography extends TailwindElement(css`\n\t:host {\n\t\tdisplay: block;\n\t\tfont-family: inherit;\n\t\thyphens: none;\n\t}\n\n\t/* Text alignment */\n\t:host([align='center']) {\n\t\ttext-align: center;\n\t}\n\n\t:host([align='left']) {\n\t\ttext-align: start;\n\t}\n\n\t:host([align='right']) {\n\t\ttext-align: right;\n\t}\n\n\t:host([align='justify']) {\n\t\ttext-align: justify;\n\t}\n\n\t/* Font weight */\n\t:host([weight='bold']) {\n\t\tfont-weight: 700;\n\t}\n\n\t:host([weight='medium']) {\n\t\tfont-weight: 500;\n\t}\n\n\t:host([weight='normal']) {\n\t\tfont-weight: 400;\n\t}\n\n\t/* Text transform */\n\t:host([transform='uppercase']) {\n\t\ttext-transform: uppercase;\n\t}\n\n\t:host([transform='lowercase']) {\n\t\ttext-transform: lowercase;\n\t}\n\n\t:host([transform='capitalize']) {\n\t\ttext-transform: capitalize;\n\t}\n\n\t:host([transform='normal']) {\n\t\ttext-transform: none;\n\t}\n\n\t/* Type-based weight defaults (when using Tailwind classes without token) */\n\t:host([type='display']),\n\t:host([type='headline']),\n\t:host([type='body']) {\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='label']),\n\t:host([type='subtitle']),\n\t:host([type='title']) {\n\t\tfont-weight: 500;\n\t}\n\n\t/* Display typography variants - Material Design 3 + Extended */\n\t:host([type='display'][token='xl']) {\n\t\tfont-size: 72px;\n\t\tline-height: 80px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='lg']) {\n\t\tfont-size: 57px;\n\t\tline-height: 64px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='md']) {\n\t\tfont-size: 45px;\n\t\tline-height: 52px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='sm']) {\n\t\tfont-size: 36px;\n\t\tline-height: 44px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='display'][token='xs']) {\n\t\tfont-size: 28px;\n\t\tline-height: 36px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Headline typography variants - Material Design 3 + Extended */\n\t:host([type='headline'][token='xl']) {\n\t\tfont-size: 36px;\n\t\tline-height: 44px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='lg']) {\n\t\tfont-size: 32px;\n\t\tline-height: 40px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='md']) {\n\t\tfont-size: 28px;\n\t\tline-height: 36px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='sm']) {\n\t\tfont-size: 24px;\n\t\tline-height: 32px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='headline'][token='xs']) {\n\t\tfont-size: 20px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Title typography variants - Material Design 3 + Extended */\n\t:host([type='title'][token='xl']) {\n\t\tfont-size: 24px;\n\t\tline-height: 32px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='title'][token='lg']) {\n\t\tfont-size: 22px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='title'][token='md']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='title'][token='sm']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='title'][token='xs']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Subtitle typography variants - Extended from Material Design 3 */\n\t:host([type='subtitle'][token='xl']) {\n\t\tfont-size: 20px;\n\t\tline-height: 28px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='lg']) {\n\t\tfont-size: 18px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='md']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='sm']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='subtitle'][token='xs']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Body typography variants - Material Design 3 + Extended */\n\t:host([type='body'][token='xl']) {\n\t\tfont-size: 18px;\n\t\tline-height: 28px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='lg']) {\n\t\tfont-size: 16px;\n\t\tline-height: 24px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='md']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='sm']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 400;\n\t}\n\n\t:host([type='body'][token='xs']) {\n\t\tfont-size: 10px;\n\t\tline-height: 14px;\n\t\tfont-weight: 400;\n\t}\n\n\t/* Label typography variants - Material Design 3 + Extended */\n\t:host([type='label'][token='xl']) {\n\t\tfont-size: 16px;\n\t\tline-height: 22px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='lg']) {\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='md']) {\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='sm']) {\n\t\tfont-size: 11px;\n\t\tline-height: 16px;\n\t\tfont-weight: 500;\n\t}\n\n\t:host([type='label'][token='xs']) {\n\t\tfont-size: 10px;\n\t\tline-height: 14px;\n\t\tfont-weight: 500;\n\t}\n\n\t/* Note: Custom letter-spacing, font-size, and line-height should be applied via inline styles or Tailwind classes */\n\n\t:host([editable]) {\n\t\tcursor: text;\n\t\tborder-radius: 4px;\n\t\ttransition: background 150ms;\n\t\tmin-height: 1em;\n\t}\n\t/* Editable div lives in shadow DOM so light DOM (Lit markers) is untouched */\n\t.edit {\n\t\toutline: none;\n\t\tmin-height: 1em;\n\t\tfont: inherit;\n\t\tcolor: inherit;\n\t\tletter-spacing: inherit;\n\t\tline-height: inherit;\n\t}\n\t.edit:empty::before {\n\t\tcontent: attr(data-placeholder);\n\t\tpointer-events: none;\n\t\tdisplay: block;\n\t\topacity: 0.35;\n\t}\n`) {\n\tstatic shadowRootOptions: ShadowRootInit = {\n\t\tmode: 'open',\n\t\tdelegatesFocus: true,\n\t}\n\n\t/**\n\t * @attr type - The type of the typography.\n\t * @default 'body'\n\t * @type {'display' | 'headline' | 'title' | 'subtitle' | 'body' | 'label'}\n\t */\n\t@property({ type: String, reflect: true })\n\ttype: 'display' | 'headline' | 'title' | 'subtitle' | 'body' | 'label' = 'body'\n\n\t/**\n\t * Shorthand for picking a (type, token) pair in one go. When set, derives\n\t * `type` and `token` automatically — saves the two-decisions-per-text-node\n\t * fatigue that hits when a single page has 50+ typography nodes.\n\t *\n\t * @attr preset\n\t * @type {TypographyPreset}\n\t * @example <schmancy-typography preset=\"heading-md\">Title</schmancy-typography>\n\t */\n\t@property({ type: String, reflect: true })\n\tpreset?: TypographyPreset\n\n\t/**\n\t * Render the slot wrapped in the requested semantic HTML element so screen\n\t * readers expose the right role / heading level. Without `as`, the slot\n\t * sits directly in the shadow root and the host is a generic element.\n\t *\n\t * @attr as\n\t * @type {TypographyTag}\n\t * @example <schmancy-typography preset=\"heading-md\" as=\"h2\">Section</schmancy-typography>\n\t */\n\t@property({ type: String, reflect: true })\n\tas?: TypographyTag\n\n\t/**\n\t * @attr token - The size token.\n\t * @deprecated Prefer using Tailwind responsive text classes for better responsive design.\n\t * Set token=\"\" and use class=\"text-sm md:text-base lg:text-lg\" instead.\n\t * Example: <schmancy-typography type=\"display\" token=\"\" class=\"text-2xl sm:text-3xl md:text-4xl\">\n\t * @default 'md'\n\t * @type {'xs' | 'sm' | 'md' | 'lg' | 'xl' | ''}\n\t */\n\t@property({ type: String, reflect: true })\n\ttoken: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '' = 'md'\n\n\t/**\n\t * @attr\n\t * @default inherit\n\t * @type {'left' |'center' |'right'}\n\t */\n\t@property({ type: String, reflect: true })\n\talign: 'left' | 'center' | 'justify' | 'right' | undefined\n\n\t/**\n\t * @attr\n\t * @default inherit\n\t * @type {'normal' | 'medium' |'bold'}\n\t * @public\n\t */\n\t@property({ type: String, reflect: true })\n\tweight: 'normal' | 'medium' | 'bold' | undefined\n\t\n\t/**\n\t *\n\t * @attr\n\t * @default inherit\n\t * @type {'uppercase' |'lowercase' |'capitalize' |'normal'}\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) \n\ttransform: 'uppercase' | 'lowercase' | 'capitalize' | 'normal' | undefined\n\n\t@property({ type: Number })\n\tmaxLines: 1 | 2 | 3 | 4 | 5 | 6 | undefined\n\n\t/** When true, the element becomes contenteditable and dispatches 'change' events on blur/Enter */\n\t@property({ type: Boolean, reflect: true }) editable = false\n\t/** The text value when in editable mode. Set via property binding: .value=${...} */\n\t@property({ type: String }) value = ''\n\t/** Placeholder shown when editable and empty */\n\t@property({ type: String }) placeholder = ''\n\n\tprivate _editRef = createRef<HTMLDivElement>()\n\n\tprotected override willUpdate(changed: PropertyValues): void {\n\t\tsuper.willUpdate?.(changed)\n\t\t// `preset` shorthand expands to (type, token) so the existing CSS\n\t\t// selectors keep matching without duplicating the size scale.\n\t\tif (changed.has('preset') && this.preset && PRESET_MAP[this.preset]) {\n\t\t\tconst { type, token } = PRESET_MAP[this.preset]\n\t\t\tthis.type = type as typeof this.type\n\t\t\tthis.token = token as typeof this.token\n\t\t}\n\t}\n\n\t/** Focus and select all text in editable mode */\n\tselectAll() {\n\t\tconst el = this._editRef.value\n\t\tif (!el) return\n\t\tel.focus()\n\t\tconst sel = window.getSelection()\n\t\tif (sel && el.textContent) {\n\t\t\tconst range = document.createRange()\n\t\t\trange.selectNodeContents(el)\n\t\t\tsel.removeAllRanges()\n\t\t\tsel.addRange(range)\n\t\t}\n\t}\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback()\n\n\t\tfromEvent<FocusEvent>(this, 'focusout').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\ttap(() => {\n\t\t\t\tconst el = this._editRef.value\n\t\t\t\tif (!el) return\n\t\t\t\tconst newValue = el.innerText.trim()\n\t\t\t\tif (newValue !== this.value) {\n\t\t\t\t\tthis.dispatchEvent(new CustomEvent('change', {\n\t\t\t\t\t\tdetail: { value: newValue },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}))\n\t\t\t\t}\n\t\t\t\t// Ensure truly empty so :empty CSS placeholder works\n\t\t\t\tif (!newValue) el.textContent = ''\n\t\t\t}),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\t// Clean stray <br> / whitespace nodes so :empty CSS matches\n\t\tfromEvent(this, 'input').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\ttap(() => {\n\t\t\t\tconst el = this._editRef.value\n\t\t\t\tif (el && !el.innerText.trim()) el.textContent = ''\n\t\t\t}),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tfromEvent<KeyboardEvent>(this, 'keydown').pipe(\n\t\t\tfilter(() => this.editable),\n\t\t\tfilter(e => e.key === 'Enter'),\n\t\t\ttap(e => { e.preventDefault(); (this._editRef.value ?? this).blur() }),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\t}\n\n\tprotected updated(changedProperties: Map<string, unknown>): void {\n\t\tsuper.updated(changedProperties)\n\t\tif (changedProperties.has('maxLines')) {\n\t\t\t// Remove all line-clamp classes\n\t\t\tthis.classList.remove('line-clamp-1', 'line-clamp-2', 'line-clamp-3', 'line-clamp-4', 'line-clamp-5', 'line-clamp-6')\n\t\t\t// Add the appropriate one\n\t\t\tif (this.maxLines) {\n\t\t\t\tthis.classList.add(`line-clamp-${this.maxLines}`)\n\t\t\t}\n\t\t}\n\t\tif ((changedProperties.has('value') || changedProperties.has('editable')) && this.editable) {\n\t\t\tconst el = this._editRef.value\n\t\t\tif (el && document.activeElement !== el) {\n\t\t\t\tif (this.value) {\n\t\t\t\t\tel.innerText = this.value\n\t\t\t\t} else {\n\t\t\t\t\tel.textContent = ''\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected render(): unknown {\n\t\tif (this.editable) {\n\t\t\treturn html`<div\n\t\t\t\t${ref(this._editRef)}\n\t\t\t\tclass=\"edit\"\n\t\t\t\tcontenteditable=\"true\"\n\t\t\t\tdata-placeholder=${this.placeholder ?? ''}\n\t\t\t></div>`\n\t\t}\n\t\t// `as` wraps the slot in the requested semantic tag so heading levels\n\t\t// land in the accessibility tree. Without `as` the slot is bare and\n\t\t// the host element carries the visual styling only.\n\t\tif (this.as && TAG_LITERALS[this.as]) {\n\t\t\tconst tag = TAG_LITERALS[this.as]\n\t\t\treturn staticHtml`<${tag}><slot></slot></${tag}>`\n\t\t}\n\t\treturn html`<slot></slot>`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-typography': SchmancyTypography\n\t}\n}"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,61 @@
|
|
|
1
1
|
import { TailwindElement } from '@mixins/tailwind.mixin'
|
|
2
|
-
import { css, html } from 'lit'
|
|
2
|
+
import { css, html, type PropertyValues } from 'lit'
|
|
3
3
|
import { customElement, property } from 'lit/decorators.js'
|
|
4
4
|
import { createRef, ref } from 'lit/directives/ref.js'
|
|
5
|
+
import { html as staticHtml, literal } from 'lit/static-html.js'
|
|
5
6
|
import { fromEvent } from 'rxjs'
|
|
6
7
|
import { filter, tap, takeUntil } from 'rxjs/operators'
|
|
7
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Preset → (type, token) shorthand. Saves the two-decision-per-text-node
|
|
11
|
+
* fatigue that 50+ typography nodes in a single page cause.
|
|
12
|
+
*/
|
|
13
|
+
export type TypographyPreset =
|
|
14
|
+
| 'display' | 'display-lg' | 'display-md' | 'display-sm'
|
|
15
|
+
| 'heading-lg' | 'heading-md' | 'heading-sm'
|
|
16
|
+
| 'title-lg' | 'title-md' | 'title-sm'
|
|
17
|
+
| 'body-lg' | 'body-md' | 'body-sm'
|
|
18
|
+
| 'label-lg' | 'label-md' | 'label-sm'
|
|
19
|
+
| 'caption'
|
|
20
|
+
|
|
21
|
+
const PRESET_MAP: Record<TypographyPreset, { type: string; token: string }> = {
|
|
22
|
+
'display': { type: 'display', token: 'lg' },
|
|
23
|
+
'display-lg': { type: 'display', token: 'lg' },
|
|
24
|
+
'display-md': { type: 'display', token: 'md' },
|
|
25
|
+
'display-sm': { type: 'display', token: 'sm' },
|
|
26
|
+
'heading-lg': { type: 'headline', token: 'lg' },
|
|
27
|
+
'heading-md': { type: 'headline', token: 'md' },
|
|
28
|
+
'heading-sm': { type: 'headline', token: 'sm' },
|
|
29
|
+
'title-lg': { type: 'title', token: 'lg' },
|
|
30
|
+
'title-md': { type: 'title', token: 'md' },
|
|
31
|
+
'title-sm': { type: 'title', token: 'sm' },
|
|
32
|
+
'body-lg': { type: 'body', token: 'lg' },
|
|
33
|
+
'body-md': { type: 'body', token: 'md' },
|
|
34
|
+
'body-sm': { type: 'body', token: 'sm' },
|
|
35
|
+
'label-lg': { type: 'label', token: 'lg' },
|
|
36
|
+
'label-md': { type: 'label', token: 'md' },
|
|
37
|
+
'label-sm': { type: 'label', token: 'sm' },
|
|
38
|
+
'caption': { type: 'label', token: 'sm' },
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Allowed semantic tag names for the `as` prop. Closed enum so we can
|
|
43
|
+
* use `literal` template parts safely with `lit/static-html`.
|
|
44
|
+
*/
|
|
45
|
+
export type TypographyTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span' | 'div'
|
|
46
|
+
|
|
47
|
+
const TAG_LITERALS: Record<TypographyTag, ReturnType<typeof literal>> = {
|
|
48
|
+
h1: literal`h1`,
|
|
49
|
+
h2: literal`h2`,
|
|
50
|
+
h3: literal`h3`,
|
|
51
|
+
h4: literal`h4`,
|
|
52
|
+
h5: literal`h5`,
|
|
53
|
+
h6: literal`h6`,
|
|
54
|
+
p: literal`p`,
|
|
55
|
+
span: literal`span`,
|
|
56
|
+
div: literal`div`,
|
|
57
|
+
}
|
|
58
|
+
|
|
8
59
|
// Material Design 3 typography - https://m3.material.io/styles/typography/type-scale-tokens
|
|
9
60
|
|
|
10
61
|
/**
|
|
@@ -302,6 +353,30 @@ export class SchmancyTypography extends TailwindElement(css`
|
|
|
302
353
|
@property({ type: String, reflect: true })
|
|
303
354
|
type: 'display' | 'headline' | 'title' | 'subtitle' | 'body' | 'label' = 'body'
|
|
304
355
|
|
|
356
|
+
/**
|
|
357
|
+
* Shorthand for picking a (type, token) pair in one go. When set, derives
|
|
358
|
+
* `type` and `token` automatically — saves the two-decisions-per-text-node
|
|
359
|
+
* fatigue that hits when a single page has 50+ typography nodes.
|
|
360
|
+
*
|
|
361
|
+
* @attr preset
|
|
362
|
+
* @type {TypographyPreset}
|
|
363
|
+
* @example <schmancy-typography preset="heading-md">Title</schmancy-typography>
|
|
364
|
+
*/
|
|
365
|
+
@property({ type: String, reflect: true })
|
|
366
|
+
preset?: TypographyPreset
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Render the slot wrapped in the requested semantic HTML element so screen
|
|
370
|
+
* readers expose the right role / heading level. Without `as`, the slot
|
|
371
|
+
* sits directly in the shadow root and the host is a generic element.
|
|
372
|
+
*
|
|
373
|
+
* @attr as
|
|
374
|
+
* @type {TypographyTag}
|
|
375
|
+
* @example <schmancy-typography preset="heading-md" as="h2">Section</schmancy-typography>
|
|
376
|
+
*/
|
|
377
|
+
@property({ type: String, reflect: true })
|
|
378
|
+
as?: TypographyTag
|
|
379
|
+
|
|
305
380
|
/**
|
|
306
381
|
* @attr token - The size token.
|
|
307
382
|
* @deprecated Prefer using Tailwind responsive text classes for better responsive design.
|
|
@@ -352,6 +427,17 @@ export class SchmancyTypography extends TailwindElement(css`
|
|
|
352
427
|
|
|
353
428
|
private _editRef = createRef<HTMLDivElement>()
|
|
354
429
|
|
|
430
|
+
protected override willUpdate(changed: PropertyValues): void {
|
|
431
|
+
super.willUpdate?.(changed)
|
|
432
|
+
// `preset` shorthand expands to (type, token) so the existing CSS
|
|
433
|
+
// selectors keep matching without duplicating the size scale.
|
|
434
|
+
if (changed.has('preset') && this.preset && PRESET_MAP[this.preset]) {
|
|
435
|
+
const { type, token } = PRESET_MAP[this.preset]
|
|
436
|
+
this.type = type as typeof this.type
|
|
437
|
+
this.token = token as typeof this.token
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
355
441
|
/** Focus and select all text in editable mode */
|
|
356
442
|
selectAll() {
|
|
357
443
|
const el = this._editRef.value
|
|
@@ -437,6 +523,13 @@ export class SchmancyTypography extends TailwindElement(css`
|
|
|
437
523
|
data-placeholder=${this.placeholder ?? ''}
|
|
438
524
|
></div>`
|
|
439
525
|
}
|
|
526
|
+
// `as` wraps the slot in the requested semantic tag so heading levels
|
|
527
|
+
// land in the accessibility tree. Without `as` the slot is bare and
|
|
528
|
+
// the host element carries the visual styling only.
|
|
529
|
+
if (this.as && TAG_LITERALS[this.as]) {
|
|
530
|
+
const tag = TAG_LITERALS[this.as]
|
|
531
|
+
return staticHtml`<${tag}><slot></slot></${tag}>`
|
|
532
|
+
}
|
|
440
533
|
return html`<slot></slot>`
|
|
441
534
|
}
|
|
442
535
|
}
|