@livenetworks/ashlar 2.1.3 → 2.1.4
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/components/index.js +0 -1
- package/components/ln-core/README.md +3 -3
- package/components/ln-core/dom.js +3 -3
- package/components/ln-filter/ln-filter.js +1 -1
- package/components/ln-form/ln-form-dev.scss +5 -0
- package/components/ln-form/ln-form.schema.json +6 -0
- package/components/ln-list/ln-list.js +1 -1
- package/components/ln-sort/README.md +4 -0
- package/components/ln-sort/ln-sort.js +1 -1
- package/components/ln-sort/src/ln-sort.js +8 -5
- package/components/ln-table/ln-table.js +1 -1
- package/ln-ashlar.html-data.json +1 -2
- package/package.json +1 -1
- package/theme/components/_form.scss +6 -0
- package/theme/config/mixins/_form.scss +6 -0
- package/theme/ln-ashlar-dev.scss +0 -1
- package/web-types.json +3 -3
- package/components/ln-autoresize/README.md +0 -129
- package/components/ln-autoresize/ln-autoresize-dev.scss +0 -8
- package/components/ln-autoresize/ln-autoresize.js +0 -1
- package/components/ln-autoresize/ln-autoresize.schema.json +0 -22
- package/components/ln-autoresize/src/ln-autoresize.js +0 -56
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# ln-autoresize
|
|
2
|
-
|
|
3
|
-
> Applied directly to a `<textarea data-ln-autoresize rows="1">`. It listens for native `input` events:
|
|
4
|
-
> in the handler, it resets `textarea.style.height = 'auto'`, reads `textarea.scrollHeight`, and sets
|
|
5
|
-
> `textarea.style.height = textarea.scrollHeight + 'px'`. It carries zero state, executing a synchronous layout calculation to expand and collapse the box dynamically.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 🧭 Philosophy & Architecture
|
|
10
|
-
|
|
11
|
-
1. **Platform-First Execution:** Instead of introducing heavy observers or layouts, `ln-autoresize` hooks directly into the browser's native layout engine. By resetting height to `auto` before reading `scrollHeight` inside the event loop, it forces a synchronous, flicker-free layout calculation.
|
|
12
|
-
2. **Strict Concern Scope:** The primitive is stateless. Ceiling limits, minimum bounds, and manual resize handles are defined exclusively via standard CSS classes. The script only handles active observation.
|
|
13
|
-
3. **Reactive Synchronization:** Data flows strictly through DOM events. Programmatic changes must trigger standard events (`input` / `change`) so that dependent primitives can adapt in synchrony.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## 📦 Minimal Blueprint
|
|
18
|
-
|
|
19
|
-
```html
|
|
20
|
-
<textarea data-ln-autoresize rows="1" placeholder="Type here..."></textarea>
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
To cap growth at a maximum height and enable scroll past it, pair the attribute with pure CSS:
|
|
24
|
-
|
|
25
|
-
```scss
|
|
26
|
-
textarea[data-ln-autoresize] {
|
|
27
|
-
resize: none; // Removes conflicting manual drag handle
|
|
28
|
-
max-height: 6rem; // Defines height ceiling
|
|
29
|
-
overflow-y: auto; // Reveals scrollbar at ceiling
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
> [!TIP]
|
|
34
|
-
> Always set `rows="1"` on the HTML element. This ensures the initial empty height matches the post-initialization state and prevents visual snap-shut on first paint.
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## 🛠️ Declarative API Contract
|
|
39
|
-
|
|
40
|
-
### HTML Attributes
|
|
41
|
-
|
|
42
|
-
| Attribute | Elements | Description |
|
|
43
|
-
| :--- | :--- | :--- |
|
|
44
|
-
| `data-ln-autoresize` | `<textarea>` | Observation marker. Presence creates the instance and runs initial measurement. |
|
|
45
|
-
|
|
46
|
-
### JS API
|
|
47
|
-
|
|
48
|
-
Access the utility instance directly via the `lnAutoresize` property on the textarea element:
|
|
49
|
-
|
|
50
|
-
```javascript
|
|
51
|
-
const textarea = document.getElementById('my-textarea');
|
|
52
|
-
|
|
53
|
-
// 1. Force a manual re-measure (essential after parent reveals, font loads, etc.)
|
|
54
|
-
textarea.lnAutoresize._resize();
|
|
55
|
-
|
|
56
|
-
// 2. Tear down event listeners and clear inline styles
|
|
57
|
-
textarea.lnAutoresize.destroy();
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## ⚡ DOM Events
|
|
63
|
-
|
|
64
|
-
`ln-autoresize` does not emit custom events. It relies entirely on standard browser interactions:
|
|
65
|
-
|
|
66
|
-
- **Listens to `input`:** Triggers `_resize()` on keystrokes, pastes, and deletes.
|
|
67
|
-
- **Listens to `change`:** Triggers `_resize()` on value commits.
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## ⚠️ Common Pitfalls
|
|
72
|
-
|
|
73
|
-
- **Setting `textarea.value` directly:** Programmatic writes are silent in the DOM. The component will not detect value updates unless you dispatch a synthetic event:
|
|
74
|
-
```javascript
|
|
75
|
-
textarea.value = 'New text content';
|
|
76
|
-
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
|
77
|
-
```
|
|
78
|
-
- **Mounting in hidden parents:** A textarea inside a `display: none` container measures `scrollHeight` as `0`. When revealed later, it will appear collapsed. Force a re-measure manually after reveal:
|
|
79
|
-
```javascript
|
|
80
|
-
textarea.lnAutoresize._resize();
|
|
81
|
-
```
|
|
82
|
-
- **Conflicting manual drag handles:** By default, textareas may have `resize: vertical` applied. This lets users manual resize the input, which is instantly overridden by the script on the next keystroke. Set `resize: none` to clean up the interface.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## 🔧 Internals
|
|
87
|
-
|
|
88
|
-
Source: `components/ln-autoresize/ln-autoresize.js`. A pure presentation utility — owns no data, emits no custom events, cooperates with no other component outside the `input` platform event.
|
|
89
|
-
|
|
90
|
-
### Instance state
|
|
91
|
-
|
|
92
|
-
| Property | Type | Description |
|
|
93
|
-
|----------|------|-------------|
|
|
94
|
-
| `dom` | `HTMLTextAreaElement` | The textarea, constructor argument |
|
|
95
|
-
| `_onInput` | `Function` | Bound `input` handler, kept for `destroy()` unbind |
|
|
96
|
-
|
|
97
|
-
No cached "current height" — `_resize` always reads `scrollHeight` fresh, so external CSS changes (`max-height`, font-size, padding) are picked up on the next keystroke.
|
|
98
|
-
|
|
99
|
-
### Resize mechanism
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
_resize():
|
|
103
|
-
1. style.height = 'auto'
|
|
104
|
-
2. read scrollHeight
|
|
105
|
-
3. style.height = scrollHeight + 'px'
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Step 1 is what makes it shrink, not just grow: `scrollHeight` reports the explicit `height` when content fits inside it, so without the reset every measurement would ratchet upward only. The reset + re-read happen synchronously in one tick, so the browser never paints the intermediate `auto` state — no flicker.
|
|
109
|
-
|
|
110
|
-
The constructor also calls `_resize()` once before returning, to size server-rendered pre-filled values and late-attached fields (`setAttribute` after the fact) on first paint rather than first keystroke. If the textarea is hidden at construction (`display: none` ancestor), `scrollHeight` reads `0` and there's no `ResizeObserver`/`IntersectionObserver` to catch a later reveal — call `_resize()` manually after showing it.
|
|
111
|
-
|
|
112
|
-
### Tag validation
|
|
113
|
-
|
|
114
|
-
The constructor checks `dom.tagName !== 'TEXTAREA'` and, if true, warns and returns `this` early with no `dom`/listener. The element is still marked initialized, so re-attaching the attribute after swapping in a real `<textarea>` needs `destroy()` first.
|
|
115
|
-
|
|
116
|
-
### MutationObserver via `registerComponent`
|
|
117
|
-
|
|
118
|
-
Standard shared observer on `document.body`: `childList/subtree` catches new `[data-ln-autoresize]` textareas anywhere; `attributes` (filtered to the one attribute) catches late `setAttribute` addition. Only attribute *presence* matters — no `onAttributeChange` callback, so value changes and attribute removal are no-ops.
|
|
119
|
-
|
|
120
|
-
### Destroy
|
|
121
|
-
|
|
122
|
-
Idempotent (bails if already torn down). Unbinds `_onInput`, clears `style.height` (reverting to the CSS-driven `rows`-based height), deletes the instance property. Does not remove the `data-ln-autoresize` attribute — the caller owns it, so a later rescan can re-create the instance.
|
|
123
|
-
|
|
124
|
-
### Cross-component coordination
|
|
125
|
-
|
|
126
|
-
No ln-prefixed import/listen/dispatch — only the platform `input` event. Two paths feed it synthetic `input` events:
|
|
127
|
-
|
|
128
|
-
- **`ln-form:fill`** — `ln-form`'s `fill()` writes `.value` then dispatches `input` on each populated field; autoresize catches it and re-measures. Direct `.value =` writes from project code skip this and will not resize.
|
|
129
|
-
- **`lnForm.reset()`** — walks fields dispatching synthetic `input`/`change` after `dom.reset()`, so cleared textareas shrink back. The bare native `<button type="reset">` path does NOT dispatch synthetic `input` (intentionally minimal); wire it manually or use the `lnForm.reset()` API if auto-shrink is needed there.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
@use '../../theme/config/mixins' as *;
|
|
2
|
-
|
|
3
|
-
[data-ln-debug] {
|
|
4
|
-
// 1. Host Element Check: data-ln-autoresize belongs only on <textarea>
|
|
5
|
-
[data-ln-autoresize]:not(textarea) {
|
|
6
|
-
@include dev-inline-error("data-ln-autoresize belongs only on <textarea> elements");
|
|
7
|
-
}
|
|
8
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(function(){"use strict";function I(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function C(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let i=null;for(let r=1;r<t.length;r++)if(t[r]&&t[r].nodeType===1){i=t[r];break}if(!C(i))return}e.apply(console,t)}}function Y(e,t,o){const i=o||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,i),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:i}))}function p(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){p(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}function Z(e){const t=e.querySelector('input[name="_method"]');return((t&&t.value!==""?t.value:e.method)||"").toUpperCase()}function ee(e,t){const o=!!(t&&t.typed),i=t&&t.exclude,r={},s=e.elements,l={};if(o)for(let c=0;c<s.length;c++){const n=s[c];n.name&&n.type==="checkbox"&&!n.disabled&&(l[n.name]=(l[n.name]||0)+1)}for(let c=0;c<s.length;c++){const n=s[c];if(!(!n.name||n.disabled||n.type==="file"||n.type==="submit"||n.type==="button")&&!(i&&n.matches&&n.matches(i)))if(n.type==="checkbox")o&&l[n.name]===1?r[n.name]=n.checked:(r[n.name]||(r[n.name]=[]),n.checked&&r[n.name].push(n.value));else if(n.type==="radio")n.checked&&(r[n.name]=n.value);else if(n.type==="select-multiple"){r[n.name]=[];for(let u=0;u<n.options.length;u++)n.options[u].selected&&r[n.name].push(n.options[u].value)}else if(o&&n.type==="hidden")r[n.name]=n.value;else if(o&&(n.type==="number"||n.type==="range")){const u=Number(n.value);r[n.name]=n.value===""||isNaN(u)?null:u}else r[n.name]=n.value}return r}function te(e){if(typeof e!="string")return!!e;const t=e.trim().toLowerCase();return t!=="false"&&t!=="0"&&t!==""&&t!=="off"&&t!=="no"}function ne(e,t){const o=e.elements,i=[],r={};for(let s=0;s<o.length;s++){const l=o[s];l.name&&l.type==="checkbox"&&(r[l.name]=(r[l.name]||0)+1)}for(let s=0;s<o.length;s++){const l=o[s];if(l.type==="file"||l.type==="submit"||l.type==="button")continue;const c=l.getAttribute("data-ln-fill-as")||l.name;if(!c||!(c in t))continue;const n=t[c];if(l.type==="checkbox"){if(Array.isArray(n))l.checked=n.indexOf(l.value)!==-1;else if(r[l.name]>1){const u=String(n).split(",").map(function(a){return a.trim()});l.checked=u.indexOf(l.value)!==-1}else l.checked=te(n);i.push(l)}else if(l.type==="radio")l.checked=l.value===String(n),i.push(l);else if(l.type==="select-multiple"){if(Array.isArray(n))for(let u=0;u<l.options.length;u++)l.options[u].selected=n.indexOf(l.options[u].value)!==-1;i.push(l)}else l.value=n,l.tagName==="SELECT"&&n!=null&&l.setAttribute("data-ln-value",n),i.push(l)}return i}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.populateForm=ne,window.lnCore.serializeForm=ee,window.lnCore.resolveFormMethod=Z);const T={};function oe(e,t){T[e]=t}function re(e){return T[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=oe,window.lnCore.getDataMapper=re);function ie(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,p(function(){new MutationObserver(function(){Y(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const q={};function le(e,t){if(!e||typeof t!="object")return;const o=e.toLowerCase().split("-")[0];q[o]=t}function se(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return q[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=le,window.lnCore.getLocaleFallback=se,window.lnCore.ensureLocaleObserver=ie);const m={};function ce(e,t){m[e]||(m[e]=document.querySelector('[data-ln-template="'+e+'"]'));const o=m[e];return o?o.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function F(e,t){if(!e||!t)return e;const o=e.querySelectorAll("[data-ln-field]");for(let l=0;l<o.length;l++){const c=o[l],n=c.getAttribute("data-ln-field");t[n]!=null&&(c.textContent=t[n])}const i=e.querySelectorAll("[data-ln-attr]");for(let l=0;l<i.length;l++){const c=i[l],n=c.getAttribute("data-ln-attr").split(",");for(let u=0;u<n.length;u++){const a=n[u].trim().split(":");if(a.length!==2)continue;const d=a[0].trim(),f=a[1].trim();t[f]!=null&&c.setAttribute(d,t[f])}}const r=e.querySelectorAll("[data-ln-show]");for(let l=0;l<r.length;l++){const c=r[l],n=c.getAttribute("data-ln-show");n in t&&c.classList.toggle("hidden",!t[n])}const s=e.querySelectorAll("[data-ln-class]");for(let l=0;l<s.length;l++){const c=s[l],n=c.getAttribute("data-ln-class").split(",");for(let u=0;u<n.length;u++){const a=n[u].trim().split(":");if(a.length!==2)continue;const d=a[0].trim(),f=a[1].trim();f in t&&c.classList.toggle(d,!!t[f])}}return e}function ue(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const o=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let i=0;i<o.length;i++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",o[i],t??null),o[i].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)F(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let o=0;o<t.length;o++)t[o].textContent=""}})));function $(e,t){if(!e||!t)return e;const o=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;o.nextNode();){const s=o.currentNode;s.textContent.indexOf("{{")!==-1&&(s.textContent=s.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(l,c){return t[c]!==void 0?t[c]:""}))}const i=function(s,l){return t[l]!==void 0?t[l]:""},r=Array.from(e.querySelectorAll("*"));e.nodeType===1&&r.push(e);for(let s=0;s<r.length;s++){const l=r[s],c=l.attributes;for(let n=0;n<c.length;n++){const u=c[n];u.value.indexOf("{{")!==-1&&l.setAttribute(u.name,u.value.replace(/\{\{\s*(\w+)\s*\}\}/g,i))}}return e}function ae(e,t,o,i,r,s){const l={};for(let n=0;n<e.children.length;n++){const u=e.children[n],a=u.getAttribute("data-ln-render-key");a&&(l[a]=u)}const c=document.createDocumentFragment();for(let n=0;n<t.length;n++){const u=t[n],a=String(i(u));let d=l[a];if(d)r(d,u,n);else{const f=ce(o,s);if(!f||($(f,u),d=f.firstElementChild,!d))continue;d.setAttribute("data-ln-render-key",a),r(d,u,n)}c.appendChild(d)}e.textContent="",e.appendChild(c)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=$,window.lnCore.fill=F,window.lnCore.lnFill=ue,window.lnCore.renderList=ae);function y(e,t,o){const i=e.getAttribute(t);return i===null?o:i}function N(e,t,o){const i=parseInt(e.getAttribute(t),10);return isNaN(i)?o:i}function R(e,t,o=!1){const i=e.getAttribute(t);if(i===null)return!!o;const r=i.trim().toLowerCase();return!(r==="false"||r==="0")}function M(e,t){return(e.getAttribute(t)||"").split(",").map(o=>o.trim()).filter(Boolean)}const A=new Map;function B(e,t){const o=(e?e.join("|"):"")+"::"+t;if(A.has(o))return A.get(o);const i=new Set(e||[]),r=function(s,l){const c=s.getAttribute(l);return c!==null&&i.has(c)?c:t};return A.set(o,r),r}function j(e,t,o){const i=parseFloat(e.getAttribute(t));return isNaN(i)?o:i}function W(e,t,o){const i=e.getAttribute(t);if(!i)return o;try{return JSON.parse(i)}catch{return o}}function U(e,t,o,i,r){if(!e||t===null)return!0;const s=i||"ln-component",l=e.type;if(l==="trigger"||l==="marker"||l==="string"||l==="list"||!l||t===""&&e.fallback!==void 0)return!0;const c=n=>{r?console.warn(n,r):console.warn(n)};if(l==="boolean"){const n=t.trim().toLowerCase();return n!==""&&n!=="true"&&n!=="false"&&n!=="1"&&n!=="0"?(c(`[${s}] Invalid value "${t}" for boolean attribute "${o}". Allowed: "true", "false", or presence-only.`),!1):!0}if(l==="enum"){const n=e.values||[];return n.includes(t)?!0:(c(`[${s}] Invalid value "${t}" for attribute "${o}". Allowed: ${n.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(l==="integer"){if(!/^-?\d+$/.test(t))return c(`[${s}] Invalid integer "${t}" for attribute "${o}". Fallback: ${e.fallback}.`),!1;const n=parseInt(t,10);return e.min!==void 0&&n<e.min?(c(`[${s}] Value ${n} for attribute "${o}" is less than min (${e.min}).`),!1):e.max!==void 0&&n>e.max?(c(`[${s}] Value ${n} for attribute "${o}" is greater than max (${e.max}).`),!1):!0}if(l==="float")return isNaN(Number(t))?(c(`[${s}] Invalid float "${t}" for attribute "${o}". Fallback: ${e.fallback}.`),!1):!0;if(l==="json")try{return JSON.parse(t),!0}catch(n){return c(`[${s}] Invalid JSON for attribute "${o}": ${n.message}. Fallback: ${e.fallback}.`),!1}return!0}function de(e,t,o){for(const i in o){const[r,s,l]=o[i];Object.defineProperty(e,i,{get:function(){return r(t,s,l)},enumerable:!0,configurable:!0})}return e}function fe(e){const t={};for(const o in e){const i=e[o];if(!i||!i.prop)continue;let r=i.read;if(!r&&i.type)switch(i.type){case"enum":r=B(i.values,i.fallback);break;case"integer":r=N;break;case"float":r=j;break;case"boolean":r=R;break;case"list":r=M;break;case"json":r=W;break;case"string":default:r=y;break}r||(r=y),t[i.prop]=[r,o,i.fallback]}return t}function we(e){const t={};for(const o in e){const i=e[o];i&&i.effect&&(t[o]=i.effect)}return Object.keys(t).length?t:null}function he(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const o in e.effects)t.add(o);if(e.onAttrChange&&e.declared)for(const o of e.declared)t.add(o);return t}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.defineAttrs=de,window.lnCore.attrSpec=fe,window.lnCore.attrStr=y,window.lnCore.attrInt=N,window.lnCore.attrBool=R,window.lnCore.attrList=M,window.lnCore.attrEnum=B,window.lnCore.attrFloat=j,window.lnCore.attrJson=W);function h(e,t){if(!e[t.attribute]){window.lnCore._persistSink&&e.hasAttribute&&e.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(e,t.selector);try{e[t.attribute]=new t.ComponentFn(e)}catch(o){console.error("["+t.attribute+"] init failed",e,o)}}}function V(e,t,o,i){if(e.nodeType!==1)return;const s=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",l={selector:t,attribute:o,ComponentFn:i};if(e.matches&&e.matches(s)&&h(e,l),e.querySelectorAll){const c=e.querySelectorAll(s);for(let n=0;n<c.length;n++)h(c[n],l)}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function be(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function pe(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function z(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function ge(e){const t=z(),o=e.observed||[];for(let i=0;i<o.length;i++){const r=o[i];t.byAttr.has(r)||t.byAttr.set(r,[]),t.byAttr.get(r).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const i in e.attributes){t.byDeclaredAttr.has(i)||t.byDeclaredAttr.set(i,[]);const r=t.byDeclaredAttr.get(i);r.some(s=>s.componentTag===e.componentTag)||r.push({spec:e.attributes[i],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const i=he(e);if(i===null)t.reactiveWildcard.push(e);else for(const r of i)t.byReactive.has(r)||t.byReactive.set(r,[]),t.byReactive.get(r).push(e)}e.persist&&t.persist.push(e)}function H(e,t,o,i){for(let r=0;r<e.length;r++){const s=e[r];if(!t[s.attribute])continue;const l=s.effects&&s.effects[o];l?l(t,o,i):s.onAttrChange&&(!s.declared||s.declared.has(o))&&s.onAttrChange(t,o,i)}}function Ce(e){const t=e.attributeName,o=t.indexOf("data-ln-")===0,i=z(),r=i.byAttr.get(t),s=I()&&i.byDeclaredAttr&&i.byDeclaredAttr.has(t);if(!o&&!r&&!s)return;const l=e.target;if(e.oldValue!==l.getAttribute(t)){if(s&&C(l)){const c=i.byDeclaredAttr.get(t),n=l.getAttribute(t);for(let u=0;u<c.length;u++)U(c[u].spec,n,t,c[u].componentTag,l)}if(window.lnCore._debugSink&&(o||r)&&window.lnCore._debugSink("attr",t,l,{oldValue:e.oldValue,newValue:l.getAttribute(t)}),o){const c=i.byReactive.get(t);c&&H(c,l,t,e.oldValue),i.reactiveWildcard.length&&H(i.reactiveWildcard,l,t,e.oldValue)}if(r)for(let c=0;c<r.length;c++){const n=r[c];if(n.handler){n.handler(l,t,e.oldValue);continue}n.onAttributeChange&&l[n.attribute]?n.onAttributeChange(l,t):(V(l,n.selector,n.attribute,n.ComponentFn),n.onInit&&n.onInit(l))}}}function me(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,p(function(){new MutationObserver(function(t){for(let o=0;o<t.length;o++)try{Ce(t[o])}catch(i){console.error("[ln-core] mutation handler failed",t[o].target,i)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function x(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function v(){return window.lnCore=window.lnCore||{},window.lnCore._subtreeRegistry=window.lnCore._subtreeRegistry||[]}function _(e,t){if(!document.contains(e))if(t.attribute){const o=e[t.attribute];if(o&&typeof o.destroy=="function")try{o.destroy()}catch(i){console.error("["+t.attribute+"] destroy failed",e,i)}delete e[t.attribute]}else t.onDestroy&&t.onDestroy(e)}function ye(e){const t=x();if(!t.length)return;const o=e.target;if(o){const r=o.nodeType===1?o:o.parentElement;if(r&&(r.isContentEditable||r.closest&&r.closest('[contenteditable]:not([contenteditable="false"])')))return}const i=v();if(e.target&&i.length)for(let r=0;r<i.length;r++){const s=i[r],l=s.query,c=e.target.nodeType===1?e.target.matches&&e.target.matches(l)?e.target:e.target.closest?e.target.closest(l):null:e.target.parentElement&&e.target.parentElement.closest?e.target.parentElement.closest(l):null;c&&s.onSubtreeChange(c,e)}for(let r=0;r<e.addedNodes.length;r++){const s=e.addedNodes[r];if(s.nodeType===1){const l=!!(s.firstElementChild||s.children&&s.children.length);for(let c=0;c<t.length;c++){const n=t[c];if(n.selector&&n.attribute&&n.ComponentFn){if(!l)s.matches&&s.matches(n.query)&&h(s,n);else if(s.matches&&s.matches(n.query)&&h(s,n),s.querySelectorAll){const u=s.querySelectorAll(n.query);for(let a=0;a<u.length;a++)h(u[a],n)}}n.onInit&&n.onInit(s)}}}for(let r=0;r<e.removedNodes.length;r++){const s=e.removedNodes[r];if(s.nodeType===1){const l=!!(s.firstElementChild||s.children&&s.children.length);for(let c=0;c<t.length;c++){const n=t[c],u=n.query;if(u){if(!l)s.matches&&s.matches(u)&&_(s,n);else if(s.matches&&s.matches(u)&&_(s,n),s.querySelectorAll){const a=s.querySelectorAll(u);for(let d=0;d<a.length;d++)_(a[d],n)}}}}}}function Q(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,p(function(){new MutationObserver(function(t){for(let o=0;o<t.length;o++){const i=t[o];if(i.type==="childList")try{ye(i)}catch(r){console.error("[ln-core] lifecycle handler failed",i.target,r)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function Ae(e){x().push(e),e.onSubtreeChange&&e.query&&v().push(e),Q()}function J(e,t,o,i,r={}){const s=r.extraAttributes||[],l=r.onAttributeChange||null,c=r.onSubtreeChange||null,n=r.onInit||null,u=r.onAttrChange||null,a=r.effects||null,d=r.attributes||null,f=d?we(d):a,Ie=d?new Set(Object.keys(d)):null,Te=r.persist||null;function g(E){const w=E||document.body;if(V(w,e,t,o),d&&I())for(const b in d){const Fe=d[b],O=Array.from(w.querySelectorAll("["+b+"]"));w.matches&&w.matches("["+b+"]")&&O.push(w);for(let L=0;L<O.length;L++){const D=O[L];C(D)&&U(Fe,D.getAttribute(b),b,i,D)}}n&&n(w)}const S=[];if(e.indexOf("[")!==-1){const E=/\[([\w-]+)/g;let w;for(;(w=E.exec(e))!==null;)S.push(w[1])}else S.push(e);ge({selector:e,attribute:t,componentTag:i,attributes:d,ComponentFn:o,onInit:n,observed:S.concat(s),onAttributeChange:l,onAttrChange:u,effects:f,declared:Ie,persist:Te}),me();const qe=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1,G=r.subtreeQuery||(qe?e:"["+e+"]"),P={selector:e,attribute:t,ComponentFn:o,onInit:n,onSubtreeChange:c,query:G};x().push(P),c&&G&&v().push(P),Q(),window[t]=g,typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerComponent=J,window.lnCore.observeLifecycle=Ae);function X(){be()>0?pe(function(){g(document.body)}):g(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",X):X(),g}function K(e){return(e||"").replace(/^#/,"")}function k(e){const t=e===void 0?location.hash:e,o={},i=K(t);if(!i)return o;const r=i.split("&");for(let s=0;s<r.length;s++){const l=r[s];if(!l)continue;const c=l.indexOf(":"),n=c>-1?l.slice(0,c):l,u=c>-1?l.slice(c+1):"";if(n)try{o[n]=decodeURIComponent(u)}catch{o[n]=u}}return o}function xe(e){if(!e)return null;const t=k();return e in t?t[e]:null}function ve(e,t){if(!e)return;const o=k();t==null?delete o[e]:o[e]=String(t);const r=Object.keys(o).map(function(s){const l=o[s];return l===""?s:s+":"+encodeURIComponent(l)}).join("&");K(location.hash)!==r&&(location.hash=r)}function _e(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function ke(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const o=e.getAttribute("data-ln-hash");if(o&&o.trim()!=="")return o.trim();const i=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return i?t?i+"-"+t:i:t||null}function Se(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Ee(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function Oe(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Le(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const o=e.slice(0,t),i=e.slice(t+1),r=i?i.split(",").map(function(s){try{return decodeURIComponent(s)}catch{return s}}).filter(Boolean):[];return{key:o,values:r}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=k,window.lnCore.hashGet=xe,window.lnCore.hashSet=ve,window.lnCore.hashLinkClick=_e,window.lnCore.resolveHashNamespace=ke,window.lnCore.hashSortEncode=Se,window.lnCore.hashSortDecode=Ee,window.lnCore.hashFilterEncode=Oe,window.lnCore.hashFilterDecode=Le);function De(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.uuid=De),(function(){const e="data-ln-autoresize",t="lnAutoresize";if(window[t]!==void 0)return;const o={"data-ln-autoresize":{type:"marker",description:"Automatically adjusts textarea height to match its scrollable content"}};function i(r){if(r.tagName!=="TEXTAREA")return console.warn("[ln-autoresize] Can only be applied to <textarea>, got:",r.tagName),this;this.dom=r;const s=this;return this._onInput=function(){s._resize()},r.addEventListener("input",this._onInput),this._resize(),this}i.prototype._resize=function(){const r=this.dom.style.height;this.dom.style.height="auto";const s=this.dom.scrollHeight+"px";this.dom.style.height=r===s?r:s},i.prototype.destroy=function(){this.dom[t]&&(this.dom.removeEventListener("input",this._onInput),this.dom.style.height="",delete this.dom[t])},J(e,t,i,"ln-autoresize",{attributes:o})})()})();
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$comment": "This file is partly generated. The $comment, component, generator, and each attribute's direction, sources, type, values, fallback, and description keys are owned by the generator and synchronized from JS source code. All other keys are preserved and safe to hand-author. Regenerate with `npm run sync:ln-schemas`.",
|
|
3
|
-
"component": "ln-autoresize",
|
|
4
|
-
"generator": "scripts/sync-ln-schemas.mjs",
|
|
5
|
-
"attributes": {
|
|
6
|
-
"data-ln-autoresize": {
|
|
7
|
-
"direction": null,
|
|
8
|
-
"sources": [
|
|
9
|
-
"ln-autoresize-dev.scss",
|
|
10
|
-
"src/ln-autoresize.js"
|
|
11
|
-
],
|
|
12
|
-
"type": "marker",
|
|
13
|
-
"description": "Automatically adjusts textarea height to match its scrollable content"
|
|
14
|
-
},
|
|
15
|
-
"data-ln-debug": {
|
|
16
|
-
"direction": null,
|
|
17
|
-
"sources": [
|
|
18
|
-
"ln-autoresize-dev.scss"
|
|
19
|
-
]
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { registerComponent } from '../../ln-core';
|
|
2
|
-
|
|
3
|
-
(function () {
|
|
4
|
-
const DOM_SELECTOR = 'data-ln-autoresize';
|
|
5
|
-
const DOM_ATTRIBUTE = 'lnAutoresize';
|
|
6
|
-
|
|
7
|
-
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
8
|
-
|
|
9
|
-
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
10
|
-
const ATTRIBUTES = {
|
|
11
|
-
'data-ln-autoresize': { type: 'marker', description: 'Automatically adjusts textarea height to match its scrollable content' }
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
// ─── Component ─────────────────────────────────────────────
|
|
15
|
-
|
|
16
|
-
function _component(dom) {
|
|
17
|
-
if (dom.tagName !== 'TEXTAREA') {
|
|
18
|
-
console.warn('[ln-autoresize] Can only be applied to <textarea>, got:', dom.tagName);
|
|
19
|
-
return this;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
this.dom = dom;
|
|
23
|
-
|
|
24
|
-
const self = this;
|
|
25
|
-
this._onInput = function () {
|
|
26
|
-
self._resize();
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
dom.addEventListener('input', this._onInput);
|
|
30
|
-
|
|
31
|
-
// Initial resize (content may be pre-filled)
|
|
32
|
-
this._resize();
|
|
33
|
-
|
|
34
|
-
return this;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
_component.prototype._resize = function () {
|
|
38
|
-
const prev = this.dom.style.height;
|
|
39
|
-
this.dom.style.height = 'auto';
|
|
40
|
-
const next = this.dom.scrollHeight + 'px';
|
|
41
|
-
this.dom.style.height = (prev === next) ? prev : next;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
_component.prototype.destroy = function () {
|
|
45
|
-
if (!this.dom[DOM_ATTRIBUTE]) return;
|
|
46
|
-
this.dom.removeEventListener('input', this._onInput);
|
|
47
|
-
this.dom.style.height = '';
|
|
48
|
-
delete this.dom[DOM_ATTRIBUTE];
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// ─── Init ──────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-autoresize', {
|
|
54
|
-
attributes: ATTRIBUTES
|
|
55
|
-
});
|
|
56
|
-
})();
|