@tslite/react 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/full.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var search=require('@tslite/codemirror/search'),format=require('@tslite/format'),editor=require('@tslite/editor');function u(t={}){let{dark:s=true,layout:e="inline",mode:o="expression",segmenter:n="mustache",gutters:i=e==="block",search:a=e==="block",extensions:r=[]}=t;return {layout:e,mode:o,...o==="template"?{}:{segmenter:n},gutters:i,format:o==="program"?format.format:format.formatExpression,features:{chrome:{dark:s},theme:editor.tsliteTokenStyles},extensions:a?[search.searchEditing(),...r]:[...r]}}Object.defineProperty(exports,"searchEditing",{enumerable:true,get:function(){return search.searchEditing}});Object.defineProperty(exports,"format",{enumerable:true,get:function(){return format.format}});Object.defineProperty(exports,"formatExpression",{enumerable:true,get:function(){return format.formatExpression}});Object.defineProperty(exports,"tsliteTokenStyles",{enumerable:true,get:function(){return editor.tsliteTokenStyles}});exports.expressionFieldProps=u;
1
+ 'use strict';var search=require('@tslite/codemirror/search'),editor=require('@tslite/editor');function y(r={}){let{dark:s=true,layout:e="inline",mode:o="expression",segmenter:n="mustache",gutters:i=e==="block",search:a=e==="block",extensions:t=[]}=r;return {layout:e,mode:o,...o==="template"?{}:{segmenter:n},gutters:i,features:{chrome:{dark:s},theme:editor.tsliteTokenStyles},extensions:a?[search.searchEditing(),...t]:[...t]}}Object.defineProperty(exports,"searchEditing",{enumerable:true,get:function(){return search.searchEditing}});Object.defineProperty(exports,"tsliteTokenStyles",{enumerable:true,get:function(){return editor.tsliteTokenStyles}});exports.expressionFieldProps=y;
package/dist/full.d.cts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Extension } from '@codemirror/state';
2
- import { F as FieldLayout, S as SegmenterOption, U as UseExpressionFieldOptions } from './useExpressionField-RmyW3D9R.cjs';
2
+ import { F as FieldLayout, S as SegmenterOption, U as UseExpressionFieldOptions } from './useExpressionField-Dsh6-SIB.cjs';
3
3
  export { searchEditing } from '@tslite/codemirror/search';
4
- export { format, formatExpression } from '@tslite/format';
5
4
  export { tsliteTokenStyles } from '@tslite/editor';
6
5
  import 'react';
7
6
  import '@codemirror/view';
@@ -32,12 +31,6 @@ interface PresetOptions {
32
31
  /**
33
32
  * O que o código É. Padrão: `"expression"`.
34
33
  *
35
- * Decide também qual formatador entra: um programa é reimpresso com `;` e
36
- * quebra de statement; uma expressão, não. Injetar o de expressão num programa
37
- * faz o `parseExpression` lançar, e o serviço então declara que não sabe
38
- * formatar — em silêncio. Foi um defeito real, e é por isso que o preset
39
- * escolhe por você.
40
- *
41
34
  * **`"template"`** liga o controle de fluxo (`{% if %}` / `{% for %}` /
42
35
  * `{# #}`). Ele não é o padrão porque um `{%` literal no texto deixaria de ser
43
36
  * texto — e num campo que hoje aceita qualquer string isso seria mudança de
@@ -62,8 +55,8 @@ interface PresetOptions {
62
55
  /** Extensões suas, acrescentadas às do preset. */
63
56
  readonly extensions?: readonly Extension[];
64
57
  }
65
- /** As props que o preset resolve — o resto (`value`, `onChange`, `env`) é seu. */
66
- type PresetProps = Pick<UseExpressionFieldOptions, "layout" | "mode" | "segmenter" | "gutters" | "format" | "features" | "extensions">;
58
+ /** As props que o preset resolve — o resto (`value`, `onChange`, `world`) é seu. */
59
+ type PresetProps = Pick<UseExpressionFieldOptions, "layout" | "mode" | "segmenter" | "gutters" | "features" | "extensions">;
67
60
  /**
68
61
  * As props de um campo que já nasce certo.
69
62
  *
@@ -75,7 +68,7 @@ type PresetProps = Pick<UseExpressionFieldOptions, "layout" | "mode" | "segmente
75
68
  * {...expressionFieldProps()}
76
69
  * value={v}
77
70
  * onChange={setV}
78
- * env={env}
71
+ * world={world}
79
72
  * />
80
73
  * ```
81
74
  *
package/dist/full.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Extension } from '@codemirror/state';
2
- import { F as FieldLayout, S as SegmenterOption, U as UseExpressionFieldOptions } from './useExpressionField-RmyW3D9R.js';
2
+ import { F as FieldLayout, S as SegmenterOption, U as UseExpressionFieldOptions } from './useExpressionField-Dsh6-SIB.js';
3
3
  export { searchEditing } from '@tslite/codemirror/search';
4
- export { format, formatExpression } from '@tslite/format';
5
4
  export { tsliteTokenStyles } from '@tslite/editor';
6
5
  import 'react';
7
6
  import '@codemirror/view';
@@ -32,12 +31,6 @@ interface PresetOptions {
32
31
  /**
33
32
  * O que o código É. Padrão: `"expression"`.
34
33
  *
35
- * Decide também qual formatador entra: um programa é reimpresso com `;` e
36
- * quebra de statement; uma expressão, não. Injetar o de expressão num programa
37
- * faz o `parseExpression` lançar, e o serviço então declara que não sabe
38
- * formatar — em silêncio. Foi um defeito real, e é por isso que o preset
39
- * escolhe por você.
40
- *
41
34
  * **`"template"`** liga o controle de fluxo (`{% if %}` / `{% for %}` /
42
35
  * `{# #}`). Ele não é o padrão porque um `{%` literal no texto deixaria de ser
43
36
  * texto — e num campo que hoje aceita qualquer string isso seria mudança de
@@ -62,8 +55,8 @@ interface PresetOptions {
62
55
  /** Extensões suas, acrescentadas às do preset. */
63
56
  readonly extensions?: readonly Extension[];
64
57
  }
65
- /** As props que o preset resolve — o resto (`value`, `onChange`, `env`) é seu. */
66
- type PresetProps = Pick<UseExpressionFieldOptions, "layout" | "mode" | "segmenter" | "gutters" | "format" | "features" | "extensions">;
58
+ /** As props que o preset resolve — o resto (`value`, `onChange`, `world`) é seu. */
59
+ type PresetProps = Pick<UseExpressionFieldOptions, "layout" | "mode" | "segmenter" | "gutters" | "features" | "extensions">;
67
60
  /**
68
61
  * As props de um campo que já nasce certo.
69
62
  *
@@ -75,7 +68,7 @@ type PresetProps = Pick<UseExpressionFieldOptions, "layout" | "mode" | "segmente
75
68
  * {...expressionFieldProps()}
76
69
  * value={v}
77
70
  * onChange={setV}
78
- * env={env}
71
+ * world={world}
79
72
  * />
80
73
  * ```
81
74
  *
package/dist/full.js CHANGED
@@ -1 +1 @@
1
- import {searchEditing}from'@tslite/codemirror/search';export{searchEditing}from'@tslite/codemirror/search';import {format,formatExpression}from'@tslite/format';export{format,formatExpression}from'@tslite/format';import {tsliteTokenStyles}from'@tslite/editor';export{tsliteTokenStyles}from'@tslite/editor';function u(t={}){let{dark:s=true,layout:e="inline",mode:o="expression",segmenter:n="mustache",gutters:i=e==="block",search:a=e==="block",extensions:r=[]}=t;return {layout:e,mode:o,...o==="template"?{}:{segmenter:n},gutters:i,format:o==="program"?format:formatExpression,features:{chrome:{dark:s},theme:tsliteTokenStyles},extensions:a?[searchEditing(),...r]:[...r]}}export{u as expressionFieldProps};
1
+ import {searchEditing}from'@tslite/codemirror/search';export{searchEditing}from'@tslite/codemirror/search';import {tsliteTokenStyles}from'@tslite/editor';export{tsliteTokenStyles}from'@tslite/editor';function y(r={}){let{dark:s=true,layout:e="inline",mode:o="expression",segmenter:n="mustache",gutters:i=e==="block",search:a=e==="block",extensions:t=[]}=r;return {layout:e,mode:o,...o==="template"?{}:{segmenter:n},gutters:i,features:{chrome:{dark:s},theme:tsliteTokenStyles},extensions:a?[searchEditing(),...t]:[...t]}}export{y as expressionFieldProps};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var n=require('react'),state=require('@codemirror/state'),view=require('@codemirror/view'),commands=require('@codemirror/commands'),autocomplete=require('@codemirror/autocomplete'),codemirror=require('@tslite/codemirror'),editor=require('@tslite/editor'),languageService=require('@tslite/language-service'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var n__namespace=/*#__PURE__*/_interopNamespace(n);var ae={mustache:languageService.mustache,whole:languageService.whole},le=t=>typeof t=="function"?t:ae[t];function A(t){let{env:o,service:l,segmenter:i="mustache",mode:s="expression",profile:c,limits:d,unused:p,format:a,optional:g}=t;return n__namespace.useMemo(()=>{if(l)return l;if(!o)return null;let x={env:o,...c?{profile:c}:{},...d?{limits:d}:{},...p!==void 0?{unused:p}:{},...a?{format:a}:{},...g?{optional:g}:{}};return s==="template"?editor.createHostService({...x,mode:s}):editor.createHostService({...x,segmenter:le(i),mode:s})},[l,o,i,s,c,d,p,a,g])}var Oe=view.EditorView.theme({".cm-scroller":{overflowX:"auto",overflowY:"hidden"},".cm-content":{padding:"6px 8px"},".cm-line":{padding:"0"},"&.cm-focused":{outline:"none"}}),z=6,Le=view.EditorView.theme({".cm-scroller":{overflowY:"auto"},".cm-content":{padding:`${z}px 8px`},".cm-line":{padding:"0"},"&.cm-focused":{outline:"none"}}),Te=(t,o)=>`${o*t.defaultLineHeight+2*z}px`,we=view.EditorView.theme({"&":{height:"100%"},".cm-scroller":{overflowY:"auto"},".cm-content":{padding:"8px"},"&.cm-focused":{outline:"none"}}),$=t=>t.replace(/\r?\n/g," "),ke=(t,o)=>{if(t===false)return [];let l=o==="block"?{}:{tab:false,indentOnInput:false};return codemirror.codeEditing(typeof t=="object"?{...l,...t}:l)},Ce=t=>t?codemirror.gutters(typeof t=="object"?t:{}):[];function D(t){let{value:o,onChange:l,onCommit:i,layout:s="inline",maxLines:c,wrap:d=s!=="inline",editing:p,gutters:a,readOnly:g=false,placeholder:x,features:I,tooltipParent:T,onTokenAction:V,isTokenActionable:_,definition:w,extensions:ee}=t,h=A(t),k=n__namespace.useRef(null),v=n__namespace.useRef(null),[U,Y]=n__namespace.useState(null),[te,oe]=n__namespace.useState(false),R=n__namespace.useRef({value:o,onChange:l,onCommit:i,onTokenAction:V,isTokenActionable:_});R.current={value:o,onChange:l,onCommit:i,onTokenAction:V,isTokenActionable:_};let C=n__namespace.useCallback(e=>{let{value:r,onCommit:E}=R.current;if(!E)return;let f=e.state.doc.toString();f!==r&&E(f);},[]),u=n__namespace.useRef({service:new state.Compartment,layout:new state.Compartment,editable:new state.Compartment,actions:new state.Compartment}).current,H=n__namespace.useCallback(e=>e?codemirror.languageService(e,{theme:editor.tsliteTokenStyles,...T!==null?{tooltipParent:T??(typeof document<"u"?document.body:void 0)}:{},...I}):[],[I,T]),G=n__namespace.useCallback(e=>autocomplete.completionStatus(e.state)==="active"?autocomplete.acceptCompletion(e)||true:(C(e),true),[C]),P=n__namespace.useCallback((e,r,E,f)=>[e==="block"?[...r?[view.EditorView.lineWrapping]:[],we]:e==="grow"?[...r?[view.EditorView.lineWrapping]:[],Le,state.Prec.highest(view.keymap.of([{key:"Enter",run:G},{key:"Shift-Enter",run:commands.insertNewlineAndIndent}]))]:[codemirror.singleLine,Oe],ke(E,e),Ce(f)],[G]),M=n__namespace.useCallback(()=>{let e=[];return R.current.onTokenAction&&e.push(codemirror.tokenAction({actionable:r=>R.current.isTokenActionable?.(r)??true,onAction:r=>R.current.onTokenAction?.(r)})),w&&h?.definitionAt&&e.push(codemirror.gotoDefinition(w)),e},[w,h]);n__namespace.useEffect(()=>{if(!k.current)return;let e=new view.EditorView({parent:k.current,state:state.EditorState.create({doc:s==="inline"?$(o):o,extensions:[commands.history(),u.service.of(H(h)),u.layout.of(P(s,d,p,a)),u.editable.of(view.EditorView.editable.of(!g)),u.actions.of(M()),...x?[view.placeholder(x)]:[],view.keymap.of([...commands.historyKeymap,...commands.defaultKeymap]),view.EditorView.updateListener.of(r=>{if(r.focusChanged&&oe(r.view.hasFocus),!r.docChanged)return;r.transactions.some(f=>f.annotation(codemirror.externalChange))||R.current.onChange?.(r.state.doc.toString());}),view.EditorView.contentAttributes.of({"aria-label":x??"expression"}),view.EditorView.domEventHandlers({blur:(r,E)=>{let f=r.relatedTarget;return f instanceof Element&&(E.dom.contains(f)||f.closest(".cm-tooltip"))||C(E),false}}),...ee??[]]})});return v.current=e,Y(e),()=>{e.destroy(),v.current=null,Y(null);}},[]),n__namespace.useEffect(()=>{v.current?.dispatch({effects:u.service.reconfigure(H(h))});},[h,H,u]),n__namespace.useEffect(()=>{v.current?.dispatch({effects:u.layout.reconfigure(P(s,d,p,a))});},[s,d,p,a,P,u]),n__namespace.useEffect(()=>{v.current?.dispatch({effects:u.editable.reconfigure(view.EditorView.editable.of(!g))});},[g,u]),n__namespace.useEffect(()=>{let e=v.current;e&&(e.scrollDOM.style.maxHeight=s==="grow"&&c!==void 0&&c>0?Te(e,c):"");},[s,c,U]),n__namespace.useEffect(()=>{v.current?.dispatch({effects:u.actions.reconfigure(M())});},[M,u]),n__namespace.useEffect(()=>{let e=v.current;if(!e)return;let r=s==="inline"?$(o):o;if(r===e.state.doc.toString())return;let{anchor:E,head:f}=e.state.selection.main,N=re=>Math.min(re,r.length);e.dispatch({changes:{from:0,to:e.state.doc.length,insert:r},selection:{anchor:N(E),head:N(f)},annotations:codemirror.externalChange.of(true)});},[o,s]);let ne=n__namespace.useCallback(()=>v.current?.focus(),[]);return {ref:k,view:U,focused:te,service:h,focus:ne}}var X=n__namespace.createContext(null);function q(){let t=n__namespace.useContext(X);if(!t)throw new Error("useFieldContext must be used inside <ExpressionField.Root>");return t}var He=["value","onChange","onCommit","layout","maxLines","wrap","editing","gutters","readOnly","placeholder","features","tooltipParent","onTokenAction","isTokenActionable","definition","extensions","env","service","segmenter","mode","profile","limits","unused","format","optional"];var J=n__namespace.forwardRef(function(o,l){let{children:i,...s}=o,c={},d={};for(let[a,g]of Object.entries(s))(He.includes(a)?c:d)[a]=g;let p=D(c);return jsxRuntime.jsx(X.Provider,{value:p,children:jsxRuntime.jsx("div",{ref:l,...d,children:typeof i=="function"?i(p):i})})}),Q=n__namespace.forwardRef(function(o,l){let i=q();return jsxRuntime.jsx("div",{ref:i.ref,...o})}),Z=n__namespace.forwardRef(function({children:o,...l},i){return jsxRuntime.jsx("button",{ref:i,type:"button",...l,children:o})}),S={Root:J,Editor:Q,ExpandTrigger:Z};var y={fg:"var(--foreground, #cccccc)",mutedFg:"var(--muted-foreground, #8b8b8b)",border:"var(--border, #2b2b2b)",ring:"var(--ring, #0078d4)",input:"var(--input, transparent)",destructive:"var(--destructive, #f14c4c)",font:"var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace)"},Pe=["--foreground","--muted-foreground","--border","--ring","--input","--destructive","--font-mono","--muted","--popover","--popover-foreground","--primary","--primary-foreground","--secondary","--accent"];var Me=jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:jsxRuntime.jsx("path",{d:"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"})});function Ae({invalid:t,className:o,style:l,onExpand:i,expandIcon:s,multiline:c,layout:d,...p}){let a=d??(c?"block":"inline");return jsxRuntime.jsx(S.Root,{...p,layout:a,className:o,children:g=>jsxRuntime.jsxs("div",{style:{position:"relative",border:`1px solid ${t?y.destructive:g.focused?y.ring:y.border}`,borderRadius:"6px",backgroundColor:y.input,color:y.fg,fontFamily:y.font,fontSize:"13px",overflow:"hidden",...a==="block"?{height:"100%",display:"flex",flexDirection:"column"}:{},...l},children:[jsxRuntime.jsx(S.Editor,{style:a==="block"?{flex:1,minHeight:0}:a==="grow"?{paddingRight:i?"28px":void 0}:{paddingRight:i?"24px":void 0}}),i&&jsxRuntime.jsx(S.ExpandTrigger,{onClick:i,"aria-label":"Expandir",title:"Expandir",onMouseEnter:x=>x.currentTarget.style.opacity="1",onMouseLeave:x=>x.currentTarget.style.opacity="0.55",style:{position:"absolute",top:a==="inline"?"50%":"6px",right:"4px",transform:a==="inline"?"translateY(-50%)":void 0,display:"flex",alignItems:"center",justifyContent:"center",width:"20px",height:"20px",padding:0,lineHeight:0,border:"none",borderRadius:"4px",background:y.input,color:y.mutedFg,cursor:"pointer",opacity:.55},children:s??Me})]})})}var Ie="1.3.0";exports.CSS_VARS=Pe;exports.ExpressionField=S;exports.ExpressionFieldEditor=Q;exports.ExpressionFieldExpandTrigger=Z;exports.ExpressionFieldRoot=J;exports.ExpressionInput=Ae;exports.V=y;exports.useExpressionField=D;exports.useFieldContext=q;exports.useLanguageService=A;exports.version=Ie;
1
+ 'use strict';var n=require('react'),state=require('@codemirror/state'),view=require('@codemirror/view'),commands=require('@codemirror/commands'),autocomplete=require('@codemirror/autocomplete'),codemirror=require('@tslite/codemirror'),editor=require('@tslite/editor'),languageService=require('@tslite/language-service'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var n__namespace=/*#__PURE__*/_interopNamespace(n);var xe={mustache:languageService.mustache,whole:languageService.whole},ye=t=>typeof t=="function"?t:xe[t];function N(t){let{world:o,service:s,segmenter:a="mustache",mode:m="expression",type:i,optional:d,profile:u,guards:c}=t,f=n__namespace.useMemo(()=>{if(s||!o)return null;let y={world:o,...i!==void 0?{type:i}:{},...d?{optional:d}:{}},R={...u?{profile:u}:{},...c?{guards:c}:{}};return m==="template"?editor.createHostService({...y,...R,mode:m}):editor.createHostService({...y,...R,segmenter:ye(a),mode:m})},[s,o,a,m,i,d,u,c]);return n__namespace.useEffect(()=>f?()=>f.dispose():void 0,[f]),s??f}var Pe=view.EditorView.theme({".cm-scroller":{overflowX:"auto",overflowY:"hidden"},".cm-content":{padding:"6px 8px"},".cm-line":{padding:"0"},"&.cm-focused":{outline:"none"}}),ne=6,Me=view.EditorView.theme({".cm-scroller":{overflowY:"auto"},".cm-content":{padding:`${ne}px 8px`},".cm-line":{padding:"0"},"&.cm-focused":{outline:"none"}}),Ae=(t,o)=>`${o*t.defaultLineHeight+2*ne}px`,De=view.EditorView.theme({"&":{height:"100%"},".cm-scroller":{overflowY:"auto"},".cm-content":{padding:"8px"},"&.cm-focused":{outline:"none"}}),Ie=t=>t.replace(/\r?\n/g," "),S=(t,o)=>o==="inline"?Ie(t):t,Ve=(t,o)=>{if(t===false)return [];let s=o==="block"?{}:{tab:false,indentOnInput:false};return codemirror.codeEditing(typeof t=="object"?{...s,...t}:s)},_e=t=>t?codemirror.gutters(typeof t=="object"?t:{}):[];function B(t){let{value:o,onChange:s,onCommit:a,onFinish:m,layout:i="inline",maxLines:d,wrap:u=i!=="inline",editing:c,gutters:f,readOnly:y=false,placeholder:R,features:W,tooltipParent:A,onTokenAction:$,isTokenActionable:z,definition:D,extensions:le}=t,F=N(t),I=n__namespace.useRef(null),v=n__namespace.useRef(null),[X,q]=n__namespace.useState(null),[de,pe]=n__namespace.useState(false),h=n__namespace.useRef({value:o,layout:i,onChange:s,onCommit:a,onFinish:m,onTokenAction:$,isTokenActionable:z});h.current={value:o,layout:i,onChange:s,onCommit:a,onFinish:m,onTokenAction:$,isTokenActionable:z};let O=n__namespace.useCallback(e=>{let{value:r,layout:l}=h.current;return e.state.doc.toString()!==S(r,l)},[]),V=n__namespace.useCallback((e,r)=>{let l=O(e);l&&h.current.onCommit?.(e.state.doc.toString()),h.current.onFinish?.({via:r,dirty:l});},[O]),_=n__namespace.useCallback(e=>{let{onFinish:r,value:l,layout:p}=h.current;if(!r||autocomplete.completionStatus(e.state)==="active")return false;let L=O(e);if(L){let T=S(l,p);e.dispatch({changes:{from:0,to:e.state.doc.length,insert:T},selection:{anchor:T.length},annotations:codemirror.externalChange.of(true)});}return r({via:"escape",dirty:L}),true},[O]),g=n__namespace.useRef({service:new state.Compartment,layout:new state.Compartment,editable:new state.Compartment,actions:new state.Compartment}).current,U=n__namespace.useCallback(e=>e?codemirror.languageService(e,{theme:editor.tsliteTokenStyles,...A!==null?{tooltipParent:A??(typeof document<"u"?document.body:void 0)}:{},...W}):[],[W,A]),J=n__namespace.useCallback(e=>autocomplete.completionStatus(e.state)==="active"?autocomplete.acceptCompletion(e)||true:(V(e,"enter"),true),[V]),Y=n__namespace.useCallback((e,r,l,p)=>[e==="block"?[...r?[view.EditorView.lineWrapping]:[],De]:e==="grow"?[...r?[view.EditorView.lineWrapping]:[],Me,state.Prec.highest(view.keymap.of([{key:"Enter",run:J},{key:"Shift-Enter",run:commands.insertNewlineAndIndent},{key:"Escape",run:_}]))]:[codemirror.singleLine,Pe,state.Prec.highest(view.keymap.of([{key:"Escape",run:_}]))],Ve(l,e),_e(p)],[J,_]),G=n__namespace.useCallback(()=>{let e=[];return h.current.onTokenAction&&e.push(codemirror.tokenAction({actionable:r=>h.current.isTokenActionable?.(r)??true,onAction:r=>h.current.onTokenAction?.(r)})),D&&F?.definitionAt&&e.push(codemirror.gotoDefinition(D)),e},[D,F]);n__namespace.useEffect(()=>{if(!I.current)return;let e=new view.EditorView({parent:I.current,state:state.EditorState.create({doc:S(o,i),extensions:[commands.history(),g.service.of(U(F)),g.layout.of(Y(i,u,c,f)),g.editable.of(view.EditorView.editable.of(!y)),g.actions.of(G()),...R?[view.placeholder(R)]:[],view.keymap.of([...commands.historyKeymap,...commands.defaultKeymap]),view.EditorView.updateListener.of(r=>{if(r.focusChanged&&pe(r.view.hasFocus),!r.docChanged)return;r.transactions.some(p=>p.annotation(codemirror.externalChange))||h.current.onChange?.(r.state.doc.toString());}),view.EditorView.contentAttributes.of({"aria-label":R??"expression"}),view.EditorView.domEventHandlers({blur:(r,l)=>{let p=r.relatedTarget;return p instanceof Element&&(l.dom.contains(p)||p.closest(".cm-tooltip"))||V(l,"blur"),false}}),...le??[]]})});return v.current=e,q(e),()=>{e.destroy(),v.current=null,q(null);}},[]),n__namespace.useEffect(()=>{v.current?.dispatch({effects:g.service.reconfigure(U(F))});},[F,U,g]),n__namespace.useEffect(()=>{v.current?.dispatch({effects:g.layout.reconfigure(Y(i,u,c,f))});},[i,u,c,f,Y,g]),n__namespace.useEffect(()=>{v.current?.dispatch({effects:g.editable.reconfigure(view.EditorView.editable.of(!y))});},[y,g]),n__namespace.useEffect(()=>{let e=v.current;e&&(e.scrollDOM.style.maxHeight=i==="grow"&&d!==void 0&&d>0?Ae(e,d):"");},[i,d,X]),n__namespace.useEffect(()=>{v.current?.dispatch({effects:g.actions.reconfigure(G())});},[G,g]);let Q=n__namespace.useRef({value:o,layout:i});n__namespace.useEffect(()=>{let e=v.current;if(!e)return;let r=Q.current;Q.current={value:o,layout:i};let l=e.state.doc.toString(),p=o!==r.value||l===S(o,r.layout)?S(o,i):S(l,i);if(p===l)return;let{anchor:L,head:T}=e.state.selection.main,Z=fe=>Math.min(fe,p.length);e.dispatch({changes:{from:0,to:e.state.doc.length,insert:p},selection:{anchor:Z(L),head:Z(T)},annotations:codemirror.externalChange.of(true)});},[o,i]);let ue=n__namespace.useCallback(()=>v.current?.focus(),[]);return {ref:I,view:X,focused:de,service:F,focus:ue}}var w=class extends Error{constructor(o,s){super(s),this.name="ExpressionFieldError",this.code=o;}};var re=n__namespace.createContext(null);function ie(){let t=n__namespace.useContext(re);if(!t)throw new w("outside-root","useFieldContext must be used inside <ExpressionField.Root>");return t}var Ue=["value","onChange","onCommit","onFinish","layout","maxLines","wrap","editing","gutters","readOnly","placeholder","features","tooltipParent","onTokenAction","isTokenActionable","definition","extensions","world","service","segmenter","mode","type","optional","profile","guards"];var se=n__namespace.forwardRef(function(o,s){let{children:a,...m}=o,i={},d={};for(let[c,f]of Object.entries(m))(Ue.includes(c)?i:d)[c]=f;let u=B(i);return jsxRuntime.jsx(re.Provider,{value:u,children:jsxRuntime.jsx("div",{ref:s,...d,children:typeof a=="function"?a(u):a})})}),ae=n__namespace.forwardRef(function(o,s){let a=ie();return jsxRuntime.jsx("div",{ref:a.ref,...o})}),ce=n__namespace.forwardRef(function({children:o,...s},a){return jsxRuntime.jsx("button",{ref:a,type:"button",...s,children:o})}),C={Root:se,Editor:ae,ExpandTrigger:ce};var E={fg:"var(--foreground, #cccccc)",mutedFg:"var(--muted-foreground, #8b8b8b)",border:"var(--border, #2b2b2b)",ring:"var(--ring, #0078d4)",input:"var(--input, transparent)",destructive:"var(--destructive, #f14c4c)",font:"var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace)"},Ye=["--foreground","--muted-foreground","--border","--ring","--input","--destructive","--font-mono","--muted","--popover","--popover-foreground","--primary","--primary-foreground","--secondary","--accent"];var Ge=jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:jsxRuntime.jsx("path",{d:"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"})});function Ne({invalid:t,className:o,style:s,onExpand:a,expandIcon:m,multiline:i,layout:d,...u}){let c=d??(i?"block":"inline");return jsxRuntime.jsx(C.Root,{...u,layout:c,className:o,children:f=>jsxRuntime.jsxs("div",{style:{position:"relative",border:`1px solid ${t?E.destructive:f.focused?E.ring:E.border}`,borderRadius:"6px",backgroundColor:E.input,color:E.fg,fontFamily:E.font,fontSize:"13px",overflow:"hidden",...c==="block"?{height:"100%",display:"flex",flexDirection:"column"}:{},...s},children:[jsxRuntime.jsx(C.Editor,{style:c==="block"?{flex:1,minHeight:0}:c==="grow"?{paddingRight:a?"28px":void 0}:{paddingRight:a?"24px":void 0}}),a&&jsxRuntime.jsx(C.ExpandTrigger,{onClick:a,"aria-label":"Expandir",title:"Expandir",onMouseEnter:y=>y.currentTarget.style.opacity="1",onMouseLeave:y=>y.currentTarget.style.opacity="0.55",style:{position:"absolute",top:c==="inline"?"50%":"6px",right:"4px",transform:c==="inline"?"translateY(-50%)":void 0,display:"flex",alignItems:"center",justifyContent:"center",width:"20px",height:"20px",padding:0,lineHeight:0,border:"none",borderRadius:"4px",background:E.input,color:E.mutedFg,cursor:"pointer",opacity:.55},children:m??Ge})]})})}var je="1.5.0";exports.CSS_VARS=Ye;exports.ExpressionField=C;exports.ExpressionFieldEditor=ae;exports.ExpressionFieldError=w;exports.ExpressionFieldExpandTrigger=ce;exports.ExpressionFieldRoot=se;exports.ExpressionInput=Ne;exports.V=E;exports.useExpressionField=B;exports.useFieldContext=ie;exports.useLanguageService=N;exports.version=je;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- import { U as UseExpressionFieldOptions, E as ExpressionFieldHandle } from './useExpressionField-RmyW3D9R.cjs';
3
- export { F as FieldLayout, L as LanguageServiceOptions, S as SegmenterOption, u as useExpressionField, a as useLanguageService } from './useExpressionField-RmyW3D9R.cjs';
2
+ import { U as UseExpressionFieldOptions, E as ExpressionFieldHandle } from './useExpressionField-Dsh6-SIB.cjs';
3
+ export { a as FieldFinish, F as FieldLayout, L as LanguageServiceOptions, S as SegmenterOption, u as useExpressionField, b as useLanguageService } from './useExpressionField-Dsh6-SIB.cjs';
4
4
  export { TokenActionTarget } from '@tslite/codemirror';
5
5
  import '@codemirror/state';
6
6
  import '@codemirror/view';
@@ -31,9 +31,9 @@ interface ExpressionInputProps extends UseExpressionFieldOptions {
31
31
  * O campo de expressão pronto para uso.
32
32
  *
33
33
  * ```tsx
34
- * <ExpressionInput value={v} onChange={setV} env={env} /> // "Olá {{ user.name }}"
35
- * <ExpressionInput value={v} onChange={setV} env={env} segmenter="whole" /> // "foo.bar >= 32"
36
- * <ExpressionInput value={v} onChange={setV} env={env} layout="block" /> // o modal expandido
34
+ * <ExpressionInput value={v} onChange={setV} world={world} /> // "Olá {{ user.name }}"
35
+ * <ExpressionInput value={v} onChange={setV} world={world} segmenter="whole" /> // "foo.bar >= 32"
36
+ * <ExpressionInput value={v} onChange={setV} world={world} layout="block" /> // o modal expandido
37
37
  * ```
38
38
  */
39
39
  declare function ExpressionInput({ invalid, className, style, onExpand, expandIcon, multiline, layout, ...options }: ExpressionInputProps): React.JSX.Element;
@@ -79,6 +79,16 @@ declare const ExpressionField: {
79
79
  ExpandTrigger: React.ForwardRefExoticComponent<ExpandTriggerProps & React.RefAttributes<HTMLButtonElement>>;
80
80
  };
81
81
 
82
+ /** O motivo de uma recusa. */
83
+ type ExpressionFieldErrorCode =
84
+ /** O `useFieldContext` foi chamado fora de uma `<ExpressionField.Root>`. */
85
+ "outside-root";
86
+ /** O uso errado das peças do campo. É erro de quem monta a tela, e não do autor. */
87
+ declare class ExpressionFieldError extends Error {
88
+ readonly code: ExpressionFieldErrorCode;
89
+ constructor(code: ExpressionFieldErrorCode, message: string);
90
+ }
91
+
82
92
  /** As cores de chrome. Exportadas para o consumidor reusar no que ele desenhar. */
83
93
  declare const V: {
84
94
  readonly fg: "var(--foreground, #cccccc)";
@@ -93,6 +103,6 @@ declare const V: {
93
103
  declare const CSS_VARS: readonly ["--foreground", "--muted-foreground", "--border", "--ring", "--input", "--destructive", "--font-mono", "--muted", "--popover", "--popover-foreground", "--primary", "--primary-foreground", "--secondary", "--accent"];
94
104
 
95
105
  /** A versão deste package, a do módulo de fato carregado. */
96
- declare const version = "1.3.0";
106
+ declare const version = "1.5.0";
97
107
 
98
- export { CSS_VARS, ExpressionField, Editor as ExpressionFieldEditor, type EditorProps as ExpressionFieldEditorProps, ExpandTrigger as ExpressionFieldExpandTrigger, type ExpandTriggerProps as ExpressionFieldExpandTriggerProps, ExpressionFieldHandle, Root as ExpressionFieldRoot, type RootProps as ExpressionFieldRootProps, ExpressionInput, type ExpressionInputProps, UseExpressionFieldOptions, V, useFieldContext, version };
108
+ export { CSS_VARS, ExpressionField, Editor as ExpressionFieldEditor, type EditorProps as ExpressionFieldEditorProps, ExpressionFieldError, type ExpressionFieldErrorCode, ExpandTrigger as ExpressionFieldExpandTrigger, type ExpandTriggerProps as ExpressionFieldExpandTriggerProps, ExpressionFieldHandle, Root as ExpressionFieldRoot, type RootProps as ExpressionFieldRootProps, ExpressionInput, type ExpressionInputProps, UseExpressionFieldOptions, V, useFieldContext, version };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- import { U as UseExpressionFieldOptions, E as ExpressionFieldHandle } from './useExpressionField-RmyW3D9R.js';
3
- export { F as FieldLayout, L as LanguageServiceOptions, S as SegmenterOption, u as useExpressionField, a as useLanguageService } from './useExpressionField-RmyW3D9R.js';
2
+ import { U as UseExpressionFieldOptions, E as ExpressionFieldHandle } from './useExpressionField-Dsh6-SIB.js';
3
+ export { a as FieldFinish, F as FieldLayout, L as LanguageServiceOptions, S as SegmenterOption, u as useExpressionField, b as useLanguageService } from './useExpressionField-Dsh6-SIB.js';
4
4
  export { TokenActionTarget } from '@tslite/codemirror';
5
5
  import '@codemirror/state';
6
6
  import '@codemirror/view';
@@ -31,9 +31,9 @@ interface ExpressionInputProps extends UseExpressionFieldOptions {
31
31
  * O campo de expressão pronto para uso.
32
32
  *
33
33
  * ```tsx
34
- * <ExpressionInput value={v} onChange={setV} env={env} /> // "Olá {{ user.name }}"
35
- * <ExpressionInput value={v} onChange={setV} env={env} segmenter="whole" /> // "foo.bar >= 32"
36
- * <ExpressionInput value={v} onChange={setV} env={env} layout="block" /> // o modal expandido
34
+ * <ExpressionInput value={v} onChange={setV} world={world} /> // "Olá {{ user.name }}"
35
+ * <ExpressionInput value={v} onChange={setV} world={world} segmenter="whole" /> // "foo.bar >= 32"
36
+ * <ExpressionInput value={v} onChange={setV} world={world} layout="block" /> // o modal expandido
37
37
  * ```
38
38
  */
39
39
  declare function ExpressionInput({ invalid, className, style, onExpand, expandIcon, multiline, layout, ...options }: ExpressionInputProps): React.JSX.Element;
@@ -79,6 +79,16 @@ declare const ExpressionField: {
79
79
  ExpandTrigger: React.ForwardRefExoticComponent<ExpandTriggerProps & React.RefAttributes<HTMLButtonElement>>;
80
80
  };
81
81
 
82
+ /** O motivo de uma recusa. */
83
+ type ExpressionFieldErrorCode =
84
+ /** O `useFieldContext` foi chamado fora de uma `<ExpressionField.Root>`. */
85
+ "outside-root";
86
+ /** O uso errado das peças do campo. É erro de quem monta a tela, e não do autor. */
87
+ declare class ExpressionFieldError extends Error {
88
+ readonly code: ExpressionFieldErrorCode;
89
+ constructor(code: ExpressionFieldErrorCode, message: string);
90
+ }
91
+
82
92
  /** As cores de chrome. Exportadas para o consumidor reusar no que ele desenhar. */
83
93
  declare const V: {
84
94
  readonly fg: "var(--foreground, #cccccc)";
@@ -93,6 +103,6 @@ declare const V: {
93
103
  declare const CSS_VARS: readonly ["--foreground", "--muted-foreground", "--border", "--ring", "--input", "--destructive", "--font-mono", "--muted", "--popover", "--popover-foreground", "--primary", "--primary-foreground", "--secondary", "--accent"];
94
104
 
95
105
  /** A versão deste package, a do módulo de fato carregado. */
96
- declare const version = "1.3.0";
106
+ declare const version = "1.5.0";
97
107
 
98
- export { CSS_VARS, ExpressionField, Editor as ExpressionFieldEditor, type EditorProps as ExpressionFieldEditorProps, ExpandTrigger as ExpressionFieldExpandTrigger, type ExpandTriggerProps as ExpressionFieldExpandTriggerProps, ExpressionFieldHandle, Root as ExpressionFieldRoot, type RootProps as ExpressionFieldRootProps, ExpressionInput, type ExpressionInputProps, UseExpressionFieldOptions, V, useFieldContext, version };
108
+ export { CSS_VARS, ExpressionField, Editor as ExpressionFieldEditor, type EditorProps as ExpressionFieldEditorProps, ExpressionFieldError, type ExpressionFieldErrorCode, ExpandTrigger as ExpressionFieldExpandTrigger, type ExpandTriggerProps as ExpressionFieldExpandTriggerProps, ExpressionFieldHandle, Root as ExpressionFieldRoot, type RootProps as ExpressionFieldRootProps, ExpressionInput, type ExpressionInputProps, UseExpressionFieldOptions, V, useFieldContext, version };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import*as n from'react';import {Compartment,Prec,EditorState}from'@codemirror/state';import {EditorView,keymap,placeholder}from'@codemirror/view';import {insertNewlineAndIndent,history,historyKeymap,defaultKeymap}from'@codemirror/commands';import {completionStatus,acceptCompletion}from'@codemirror/autocomplete';import {languageService,singleLine,tokenAction,gotoDefinition,externalChange,codeEditing,gutters}from'@tslite/codemirror';import {tsliteTokenStyles,createHostService}from'@tslite/editor';import {whole,mustache}from'@tslite/language-service';import {jsx,jsxs}from'react/jsx-runtime';var ae={mustache:mustache,whole:whole},le=t=>typeof t=="function"?t:ae[t];function A(t){let{env:o,service:l,segmenter:i="mustache",mode:s="expression",profile:c,limits:d,unused:p,format:a,optional:g}=t;return n.useMemo(()=>{if(l)return l;if(!o)return null;let x={env:o,...c?{profile:c}:{},...d?{limits:d}:{},...p!==void 0?{unused:p}:{},...a?{format:a}:{},...g?{optional:g}:{}};return s==="template"?createHostService({...x,mode:s}):createHostService({...x,segmenter:le(i),mode:s})},[l,o,i,s,c,d,p,a,g])}var Oe=EditorView.theme({".cm-scroller":{overflowX:"auto",overflowY:"hidden"},".cm-content":{padding:"6px 8px"},".cm-line":{padding:"0"},"&.cm-focused":{outline:"none"}}),z=6,Le=EditorView.theme({".cm-scroller":{overflowY:"auto"},".cm-content":{padding:`${z}px 8px`},".cm-line":{padding:"0"},"&.cm-focused":{outline:"none"}}),Te=(t,o)=>`${o*t.defaultLineHeight+2*z}px`,we=EditorView.theme({"&":{height:"100%"},".cm-scroller":{overflowY:"auto"},".cm-content":{padding:"8px"},"&.cm-focused":{outline:"none"}}),$=t=>t.replace(/\r?\n/g," "),ke=(t,o)=>{if(t===false)return [];let l=o==="block"?{}:{tab:false,indentOnInput:false};return codeEditing(typeof t=="object"?{...l,...t}:l)},Ce=t=>t?gutters(typeof t=="object"?t:{}):[];function D(t){let{value:o,onChange:l,onCommit:i,layout:s="inline",maxLines:c,wrap:d=s!=="inline",editing:p,gutters:a,readOnly:g=false,placeholder:x,features:I,tooltipParent:T,onTokenAction:V,isTokenActionable:_,definition:w,extensions:ee}=t,h=A(t),k=n.useRef(null),v=n.useRef(null),[U,Y]=n.useState(null),[te,oe]=n.useState(false),R=n.useRef({value:o,onChange:l,onCommit:i,onTokenAction:V,isTokenActionable:_});R.current={value:o,onChange:l,onCommit:i,onTokenAction:V,isTokenActionable:_};let C=n.useCallback(e=>{let{value:r,onCommit:E}=R.current;if(!E)return;let f=e.state.doc.toString();f!==r&&E(f);},[]),u=n.useRef({service:new Compartment,layout:new Compartment,editable:new Compartment,actions:new Compartment}).current,H=n.useCallback(e=>e?languageService(e,{theme:tsliteTokenStyles,...T!==null?{tooltipParent:T??(typeof document<"u"?document.body:void 0)}:{},...I}):[],[I,T]),G=n.useCallback(e=>completionStatus(e.state)==="active"?acceptCompletion(e)||true:(C(e),true),[C]),P=n.useCallback((e,r,E,f)=>[e==="block"?[...r?[EditorView.lineWrapping]:[],we]:e==="grow"?[...r?[EditorView.lineWrapping]:[],Le,Prec.highest(keymap.of([{key:"Enter",run:G},{key:"Shift-Enter",run:insertNewlineAndIndent}]))]:[singleLine,Oe],ke(E,e),Ce(f)],[G]),M=n.useCallback(()=>{let e=[];return R.current.onTokenAction&&e.push(tokenAction({actionable:r=>R.current.isTokenActionable?.(r)??true,onAction:r=>R.current.onTokenAction?.(r)})),w&&h?.definitionAt&&e.push(gotoDefinition(w)),e},[w,h]);n.useEffect(()=>{if(!k.current)return;let e=new EditorView({parent:k.current,state:EditorState.create({doc:s==="inline"?$(o):o,extensions:[history(),u.service.of(H(h)),u.layout.of(P(s,d,p,a)),u.editable.of(EditorView.editable.of(!g)),u.actions.of(M()),...x?[placeholder(x)]:[],keymap.of([...historyKeymap,...defaultKeymap]),EditorView.updateListener.of(r=>{if(r.focusChanged&&oe(r.view.hasFocus),!r.docChanged)return;r.transactions.some(f=>f.annotation(externalChange))||R.current.onChange?.(r.state.doc.toString());}),EditorView.contentAttributes.of({"aria-label":x??"expression"}),EditorView.domEventHandlers({blur:(r,E)=>{let f=r.relatedTarget;return f instanceof Element&&(E.dom.contains(f)||f.closest(".cm-tooltip"))||C(E),false}}),...ee??[]]})});return v.current=e,Y(e),()=>{e.destroy(),v.current=null,Y(null);}},[]),n.useEffect(()=>{v.current?.dispatch({effects:u.service.reconfigure(H(h))});},[h,H,u]),n.useEffect(()=>{v.current?.dispatch({effects:u.layout.reconfigure(P(s,d,p,a))});},[s,d,p,a,P,u]),n.useEffect(()=>{v.current?.dispatch({effects:u.editable.reconfigure(EditorView.editable.of(!g))});},[g,u]),n.useEffect(()=>{let e=v.current;e&&(e.scrollDOM.style.maxHeight=s==="grow"&&c!==void 0&&c>0?Te(e,c):"");},[s,c,U]),n.useEffect(()=>{v.current?.dispatch({effects:u.actions.reconfigure(M())});},[M,u]),n.useEffect(()=>{let e=v.current;if(!e)return;let r=s==="inline"?$(o):o;if(r===e.state.doc.toString())return;let{anchor:E,head:f}=e.state.selection.main,N=re=>Math.min(re,r.length);e.dispatch({changes:{from:0,to:e.state.doc.length,insert:r},selection:{anchor:N(E),head:N(f)},annotations:externalChange.of(true)});},[o,s]);let ne=n.useCallback(()=>v.current?.focus(),[]);return {ref:k,view:U,focused:te,service:h,focus:ne}}var X=n.createContext(null);function q(){let t=n.useContext(X);if(!t)throw new Error("useFieldContext must be used inside <ExpressionField.Root>");return t}var He=["value","onChange","onCommit","layout","maxLines","wrap","editing","gutters","readOnly","placeholder","features","tooltipParent","onTokenAction","isTokenActionable","definition","extensions","env","service","segmenter","mode","profile","limits","unused","format","optional"];var J=n.forwardRef(function(o,l){let{children:i,...s}=o,c={},d={};for(let[a,g]of Object.entries(s))(He.includes(a)?c:d)[a]=g;let p=D(c);return jsx(X.Provider,{value:p,children:jsx("div",{ref:l,...d,children:typeof i=="function"?i(p):i})})}),Q=n.forwardRef(function(o,l){let i=q();return jsx("div",{ref:i.ref,...o})}),Z=n.forwardRef(function({children:o,...l},i){return jsx("button",{ref:i,type:"button",...l,children:o})}),S={Root:J,Editor:Q,ExpandTrigger:Z};var y={fg:"var(--foreground, #cccccc)",mutedFg:"var(--muted-foreground, #8b8b8b)",border:"var(--border, #2b2b2b)",ring:"var(--ring, #0078d4)",input:"var(--input, transparent)",destructive:"var(--destructive, #f14c4c)",font:"var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace)"},Pe=["--foreground","--muted-foreground","--border","--ring","--input","--destructive","--font-mono","--muted","--popover","--popover-foreground","--primary","--primary-foreground","--secondary","--accent"];var Me=jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:jsx("path",{d:"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"})});function Ae({invalid:t,className:o,style:l,onExpand:i,expandIcon:s,multiline:c,layout:d,...p}){let a=d??(c?"block":"inline");return jsx(S.Root,{...p,layout:a,className:o,children:g=>jsxs("div",{style:{position:"relative",border:`1px solid ${t?y.destructive:g.focused?y.ring:y.border}`,borderRadius:"6px",backgroundColor:y.input,color:y.fg,fontFamily:y.font,fontSize:"13px",overflow:"hidden",...a==="block"?{height:"100%",display:"flex",flexDirection:"column"}:{},...l},children:[jsx(S.Editor,{style:a==="block"?{flex:1,minHeight:0}:a==="grow"?{paddingRight:i?"28px":void 0}:{paddingRight:i?"24px":void 0}}),i&&jsx(S.ExpandTrigger,{onClick:i,"aria-label":"Expandir",title:"Expandir",onMouseEnter:x=>x.currentTarget.style.opacity="1",onMouseLeave:x=>x.currentTarget.style.opacity="0.55",style:{position:"absolute",top:a==="inline"?"50%":"6px",right:"4px",transform:a==="inline"?"translateY(-50%)":void 0,display:"flex",alignItems:"center",justifyContent:"center",width:"20px",height:"20px",padding:0,lineHeight:0,border:"none",borderRadius:"4px",background:y.input,color:y.mutedFg,cursor:"pointer",opacity:.55},children:s??Me})]})})}var Ie="1.3.0";export{Pe as CSS_VARS,S as ExpressionField,Q as ExpressionFieldEditor,Z as ExpressionFieldExpandTrigger,J as ExpressionFieldRoot,Ae as ExpressionInput,y as V,D as useExpressionField,q as useFieldContext,A as useLanguageService,Ie as version};
1
+ import*as n from'react';import {Compartment,Prec,EditorState}from'@codemirror/state';import {EditorView,keymap,placeholder}from'@codemirror/view';import {insertNewlineAndIndent,history,historyKeymap,defaultKeymap}from'@codemirror/commands';import {completionStatus,acceptCompletion}from'@codemirror/autocomplete';import {externalChange,languageService,singleLine,tokenAction,gotoDefinition,codeEditing,gutters}from'@tslite/codemirror';import {tsliteTokenStyles,createHostService}from'@tslite/editor';import {whole,mustache}from'@tslite/language-service';import {jsx,jsxs}from'react/jsx-runtime';var xe={mustache:mustache,whole:whole},ye=t=>typeof t=="function"?t:xe[t];function N(t){let{world:o,service:s,segmenter:a="mustache",mode:m="expression",type:i,optional:d,profile:u,guards:c}=t,f=n.useMemo(()=>{if(s||!o)return null;let y={world:o,...i!==void 0?{type:i}:{},...d?{optional:d}:{}},R={...u?{profile:u}:{},...c?{guards:c}:{}};return m==="template"?createHostService({...y,...R,mode:m}):createHostService({...y,...R,segmenter:ye(a),mode:m})},[s,o,a,m,i,d,u,c]);return n.useEffect(()=>f?()=>f.dispose():void 0,[f]),s??f}var Pe=EditorView.theme({".cm-scroller":{overflowX:"auto",overflowY:"hidden"},".cm-content":{padding:"6px 8px"},".cm-line":{padding:"0"},"&.cm-focused":{outline:"none"}}),ne=6,Me=EditorView.theme({".cm-scroller":{overflowY:"auto"},".cm-content":{padding:`${ne}px 8px`},".cm-line":{padding:"0"},"&.cm-focused":{outline:"none"}}),Ae=(t,o)=>`${o*t.defaultLineHeight+2*ne}px`,De=EditorView.theme({"&":{height:"100%"},".cm-scroller":{overflowY:"auto"},".cm-content":{padding:"8px"},"&.cm-focused":{outline:"none"}}),Ie=t=>t.replace(/\r?\n/g," "),S=(t,o)=>o==="inline"?Ie(t):t,Ve=(t,o)=>{if(t===false)return [];let s=o==="block"?{}:{tab:false,indentOnInput:false};return codeEditing(typeof t=="object"?{...s,...t}:s)},_e=t=>t?gutters(typeof t=="object"?t:{}):[];function B(t){let{value:o,onChange:s,onCommit:a,onFinish:m,layout:i="inline",maxLines:d,wrap:u=i!=="inline",editing:c,gutters:f,readOnly:y=false,placeholder:R,features:W,tooltipParent:A,onTokenAction:$,isTokenActionable:z,definition:D,extensions:le}=t,F=N(t),I=n.useRef(null),v=n.useRef(null),[X,q]=n.useState(null),[de,pe]=n.useState(false),h=n.useRef({value:o,layout:i,onChange:s,onCommit:a,onFinish:m,onTokenAction:$,isTokenActionable:z});h.current={value:o,layout:i,onChange:s,onCommit:a,onFinish:m,onTokenAction:$,isTokenActionable:z};let O=n.useCallback(e=>{let{value:r,layout:l}=h.current;return e.state.doc.toString()!==S(r,l)},[]),V=n.useCallback((e,r)=>{let l=O(e);l&&h.current.onCommit?.(e.state.doc.toString()),h.current.onFinish?.({via:r,dirty:l});},[O]),_=n.useCallback(e=>{let{onFinish:r,value:l,layout:p}=h.current;if(!r||completionStatus(e.state)==="active")return false;let L=O(e);if(L){let T=S(l,p);e.dispatch({changes:{from:0,to:e.state.doc.length,insert:T},selection:{anchor:T.length},annotations:externalChange.of(true)});}return r({via:"escape",dirty:L}),true},[O]),g=n.useRef({service:new Compartment,layout:new Compartment,editable:new Compartment,actions:new Compartment}).current,U=n.useCallback(e=>e?languageService(e,{theme:tsliteTokenStyles,...A!==null?{tooltipParent:A??(typeof document<"u"?document.body:void 0)}:{},...W}):[],[W,A]),J=n.useCallback(e=>completionStatus(e.state)==="active"?acceptCompletion(e)||true:(V(e,"enter"),true),[V]),Y=n.useCallback((e,r,l,p)=>[e==="block"?[...r?[EditorView.lineWrapping]:[],De]:e==="grow"?[...r?[EditorView.lineWrapping]:[],Me,Prec.highest(keymap.of([{key:"Enter",run:J},{key:"Shift-Enter",run:insertNewlineAndIndent},{key:"Escape",run:_}]))]:[singleLine,Pe,Prec.highest(keymap.of([{key:"Escape",run:_}]))],Ve(l,e),_e(p)],[J,_]),G=n.useCallback(()=>{let e=[];return h.current.onTokenAction&&e.push(tokenAction({actionable:r=>h.current.isTokenActionable?.(r)??true,onAction:r=>h.current.onTokenAction?.(r)})),D&&F?.definitionAt&&e.push(gotoDefinition(D)),e},[D,F]);n.useEffect(()=>{if(!I.current)return;let e=new EditorView({parent:I.current,state:EditorState.create({doc:S(o,i),extensions:[history(),g.service.of(U(F)),g.layout.of(Y(i,u,c,f)),g.editable.of(EditorView.editable.of(!y)),g.actions.of(G()),...R?[placeholder(R)]:[],keymap.of([...historyKeymap,...defaultKeymap]),EditorView.updateListener.of(r=>{if(r.focusChanged&&pe(r.view.hasFocus),!r.docChanged)return;r.transactions.some(p=>p.annotation(externalChange))||h.current.onChange?.(r.state.doc.toString());}),EditorView.contentAttributes.of({"aria-label":R??"expression"}),EditorView.domEventHandlers({blur:(r,l)=>{let p=r.relatedTarget;return p instanceof Element&&(l.dom.contains(p)||p.closest(".cm-tooltip"))||V(l,"blur"),false}}),...le??[]]})});return v.current=e,q(e),()=>{e.destroy(),v.current=null,q(null);}},[]),n.useEffect(()=>{v.current?.dispatch({effects:g.service.reconfigure(U(F))});},[F,U,g]),n.useEffect(()=>{v.current?.dispatch({effects:g.layout.reconfigure(Y(i,u,c,f))});},[i,u,c,f,Y,g]),n.useEffect(()=>{v.current?.dispatch({effects:g.editable.reconfigure(EditorView.editable.of(!y))});},[y,g]),n.useEffect(()=>{let e=v.current;e&&(e.scrollDOM.style.maxHeight=i==="grow"&&d!==void 0&&d>0?Ae(e,d):"");},[i,d,X]),n.useEffect(()=>{v.current?.dispatch({effects:g.actions.reconfigure(G())});},[G,g]);let Q=n.useRef({value:o,layout:i});n.useEffect(()=>{let e=v.current;if(!e)return;let r=Q.current;Q.current={value:o,layout:i};let l=e.state.doc.toString(),p=o!==r.value||l===S(o,r.layout)?S(o,i):S(l,i);if(p===l)return;let{anchor:L,head:T}=e.state.selection.main,Z=fe=>Math.min(fe,p.length);e.dispatch({changes:{from:0,to:e.state.doc.length,insert:p},selection:{anchor:Z(L),head:Z(T)},annotations:externalChange.of(true)});},[o,i]);let ue=n.useCallback(()=>v.current?.focus(),[]);return {ref:I,view:X,focused:de,service:F,focus:ue}}var w=class extends Error{constructor(o,s){super(s),this.name="ExpressionFieldError",this.code=o;}};var re=n.createContext(null);function ie(){let t=n.useContext(re);if(!t)throw new w("outside-root","useFieldContext must be used inside <ExpressionField.Root>");return t}var Ue=["value","onChange","onCommit","onFinish","layout","maxLines","wrap","editing","gutters","readOnly","placeholder","features","tooltipParent","onTokenAction","isTokenActionable","definition","extensions","world","service","segmenter","mode","type","optional","profile","guards"];var se=n.forwardRef(function(o,s){let{children:a,...m}=o,i={},d={};for(let[c,f]of Object.entries(m))(Ue.includes(c)?i:d)[c]=f;let u=B(i);return jsx(re.Provider,{value:u,children:jsx("div",{ref:s,...d,children:typeof a=="function"?a(u):a})})}),ae=n.forwardRef(function(o,s){let a=ie();return jsx("div",{ref:a.ref,...o})}),ce=n.forwardRef(function({children:o,...s},a){return jsx("button",{ref:a,type:"button",...s,children:o})}),C={Root:se,Editor:ae,ExpandTrigger:ce};var E={fg:"var(--foreground, #cccccc)",mutedFg:"var(--muted-foreground, #8b8b8b)",border:"var(--border, #2b2b2b)",ring:"var(--ring, #0078d4)",input:"var(--input, transparent)",destructive:"var(--destructive, #f14c4c)",font:"var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace)"},Ye=["--foreground","--muted-foreground","--border","--ring","--input","--destructive","--font-mono","--muted","--popover","--popover-foreground","--primary","--primary-foreground","--secondary","--accent"];var Ge=jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:jsx("path",{d:"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"})});function Ne({invalid:t,className:o,style:s,onExpand:a,expandIcon:m,multiline:i,layout:d,...u}){let c=d??(i?"block":"inline");return jsx(C.Root,{...u,layout:c,className:o,children:f=>jsxs("div",{style:{position:"relative",border:`1px solid ${t?E.destructive:f.focused?E.ring:E.border}`,borderRadius:"6px",backgroundColor:E.input,color:E.fg,fontFamily:E.font,fontSize:"13px",overflow:"hidden",...c==="block"?{height:"100%",display:"flex",flexDirection:"column"}:{},...s},children:[jsx(C.Editor,{style:c==="block"?{flex:1,minHeight:0}:c==="grow"?{paddingRight:a?"28px":void 0}:{paddingRight:a?"24px":void 0}}),a&&jsx(C.ExpandTrigger,{onClick:a,"aria-label":"Expandir",title:"Expandir",onMouseEnter:y=>y.currentTarget.style.opacity="1",onMouseLeave:y=>y.currentTarget.style.opacity="0.55",style:{position:"absolute",top:c==="inline"?"50%":"6px",right:"4px",transform:c==="inline"?"translateY(-50%)":void 0,display:"flex",alignItems:"center",justifyContent:"center",width:"20px",height:"20px",padding:0,lineHeight:0,border:"none",borderRadius:"4px",background:E.input,color:E.mutedFg,cursor:"pointer",opacity:.55},children:m??Ge})]})})}var je="1.5.0";export{Ye as CSS_VARS,C as ExpressionField,ae as ExpressionFieldEditor,w as ExpressionFieldError,ce as ExpressionFieldExpandTrigger,se as ExpressionFieldRoot,Ne as ExpressionInput,E as V,B as useExpressionField,ie as useFieldContext,N as useLanguageService,je as version};
@@ -3,7 +3,7 @@ import { Extension } from '@codemirror/state';
3
3
  import { EditorView } from '@codemirror/view';
4
4
  import { CodeEditingOptions, GuttersOptions, LanguageServiceOptions as LanguageServiceOptions$1, TokenActionTarget, GotoDefinitionOptions } from '@tslite/codemirror';
5
5
  import { Segmenter, LanguageService, Token } from '@tslite/language-service';
6
- import { HostServiceOptions } from '@tslite/editor';
6
+ import { HostServiceOptions, HostServiceCodeOptions } from '@tslite/editor';
7
7
 
8
8
  /**
9
9
  * Onde, no texto, mora o código.
@@ -16,14 +16,16 @@ type SegmenterOption = "mustache" | "whole" | Segmenter;
16
16
  /** O que define o cérebro do campo. */
17
17
  interface LanguageServiceOptions {
18
18
  /**
19
- * O ambiente de tipos — o shape dos dados no escopo das expressões.
19
+ * O mundo em que o campo se tipa (`createWorld` do `@tslite/editor`): a lib da
20
+ * cópia do tsc, o `.d.ts` do `std` e as declarações do host. Os campos de uma
21
+ * tela dividem o mesmo mundo, e cada um é um arquivo virtual dele.
20
22
  *
21
- * **Memoize-o.** Um objeto novo a cada render reconstrói o serviço e joga
22
- * fora o cache de análise. `useMemo` no seu lado resolve.
23
+ * **Crie-o uma vez** (fora do render, ou num `useMemo`). Um mundo novo a cada
24
+ * render reconstrói o serviço e reparseia a lib.
23
25
  */
24
- readonly env?: HostServiceOptions["env"];
26
+ readonly world?: HostServiceOptions["world"];
25
27
  /**
26
- * Um serviço pronto, no lugar do `env`. Tem precedência — e é o caminho para
28
+ * Um serviço pronto, no lugar do `world`. Tem precedência — e é o caminho para
27
29
  * trocar o cérebro por outro (outra linguagem, outra implementação).
28
30
  */
29
31
  readonly service?: LanguageService;
@@ -53,19 +55,12 @@ interface LanguageServiceOptions {
53
55
  */
54
56
  readonly mode?: "expression" | "program" | "template";
55
57
  /**
56
- * Capability — **desinstala** features da Linguagem.
57
- *
58
- * Sem ela o campo só tipa, e uma atribuição (`{{ user.name = "ok" }}`) passa:
59
- * `=` existe na Linguagem completa. Não há padrão implícito aqui, porque qual
60
- * profile cabe num campo é decisão de produto.
58
+ * O tipo que o valor do campo tem de ter, como o texto de um tipo
59
+ * (`"boolean"`, `"Address"`): o campo acusa, enquanto se digita, o valor que
60
+ * não cabe nele. Vale para a expressão e para o template; um programa não tem
61
+ * valor. Sem ele, o campo aceita qualquer tipo.
61
62
  */
62
- readonly profile?: HostServiceOptions["profile"];
63
- /** Limites estruturais (anti-DoS). */
64
- readonly limits?: HostServiceOptions["limits"];
65
- /** Bindings nunca lidos. Ligado por padrão (é API de editor). */
66
- readonly unused?: HostServiceOptions["unused"];
67
- /** O formatador (`formatExpression` do `@tslite/format`). Sem ele, não formata. */
68
- readonly format?: HostServiceOptions["format"];
63
+ readonly type?: HostServiceOptions["type"];
69
64
  /**
70
65
  * O campo aceita ficar vazio: o texto vazio, ou só com espaços, é a ausência do
71
66
  * valor, e não o erro de "falta a expressão". Padrão: `false`. As sugestões no
@@ -73,10 +68,33 @@ interface LanguageServiceOptions {
73
68
  * (`createHostService({ optional })`).
74
69
  */
75
70
  readonly optional?: HostServiceOptions["optional"];
71
+ /**
72
+ * O perfil de capability do campo (o `@tslite/capability`): o que o campo pode
73
+ * escrever. O que ele recusa sai nos diagnósticos, enquanto se digita, sobre o
74
+ * texto que parseia (a E32 do `@tslite/editor`), com o veredito do executor e o da
75
+ * camada de controle. Sem padrão: sem ele, nada se poda (R18).
76
+ *
77
+ * **Crie-o uma vez**, como o `world`: um perfil novo a cada render reconstrói o
78
+ * serviço. No `mode: "template"`, ele julga o que o template desaçucara (o `map`
79
+ * de um `{% for %}`), como o executor, e a violação pousa na diretiva (a E34 do
80
+ * `@tslite/editor`). Com `service`, o perfil é de quem montou o serviço.
81
+ */
82
+ readonly profile?: HostServiceCodeOptions["profile"];
83
+ /**
84
+ * As regras a mais da camada de controle do `@tslite/behavior` (as de forma, as da
85
+ * aplicação), nos diagnósticos como as do perfil. Valem as mesmas regras do
86
+ * `profile`: crie-as uma vez.
87
+ */
88
+ readonly guards?: HostServiceCodeOptions["guards"];
76
89
  }
77
90
  /**
78
- * O `LanguageService` do campo. `null` quando não há `env` nem `service` — o
91
+ * O `LanguageService` do campo. `null` quando não há `world` nem `service` — o
79
92
  * editor continua editando texto, só sem inteligência.
93
+ *
94
+ * O serviço que o hook monta põe os arquivos virtuais do campo no mundo; quando
95
+ * ele é trocado (uma opção mudou) ou o campo desmonta, o hook os tira (o
96
+ * `dispose`, E28 do `@tslite/editor`). O `service` passado é de quem o montou, e
97
+ * o hook não o solta.
80
98
  */
81
99
  declare function useLanguageService(options: LanguageServiceOptions): LanguageService | null;
82
100
 
@@ -113,6 +131,20 @@ interface UseExpressionFieldOptions extends LanguageServiceOptions {
113
131
  * não é o autor terminando, e não commita.
114
132
  */
115
133
  readonly onCommit?: (text: string) => void;
134
+ /**
135
+ * O GESTO com que o autor terminou: o `Enter` que termina (layout `"grow"`), o
136
+ * `Escape` que cancela (layouts `"inline"` e `"grow"`) ou o foco que sai. Dispara
137
+ * também quando nada mudou, com `dirty` dizendo se havia rascunho diferente do
138
+ * `value` naquele instante (R19).
139
+ *
140
+ * No `Enter` e no blur, ele vem depois do `onCommit` (quando há o que commitar):
141
+ * quem recusa o texto no `onCommit` já recusou quando o gesto chega. O `Escape`
142
+ * volta o rascunho ao `value`, sem `onChange` nem `onCommit`, e avisa. A tecla
143
+ * que a lista de sugestões consome (o `Enter` que aceita, o `Escape` que fecha)
144
+ * não é o autor terminando, e não dispara. Sem esta função, o `Escape` não é do
145
+ * campo.
146
+ */
147
+ readonly onFinish?: (finish: FieldFinish) => void;
116
148
  /** Como o campo se apresenta. Padrão: `"inline"`. */
117
149
  readonly layout?: FieldLayout;
118
150
  /**
@@ -193,6 +225,13 @@ interface UseExpressionFieldOptions extends LanguageServiceOptions {
193
225
  /** Extensões extras do CodeMirror — a escotilha de fuga. */
194
226
  readonly extensions?: readonly Extension[];
195
227
  }
228
+ /** Como o autor terminou a edição do campo (R19). */
229
+ interface FieldFinish {
230
+ /** O gesto: o `Enter` que termina, o `Escape` que cancela, ou o foco que sai. */
231
+ readonly via: "enter" | "escape" | "blur";
232
+ /** Havia rascunho diferente do `value` quando o autor terminou. */
233
+ readonly dirty: boolean;
234
+ }
196
235
  /** O que o hook devolve. */
197
236
  interface ExpressionFieldHandle {
198
237
  /** Ponha num elemento vazio: é onde o editor monta. */
@@ -208,4 +247,4 @@ interface ExpressionFieldHandle {
208
247
  }
209
248
  declare function useExpressionField(options: UseExpressionFieldOptions): ExpressionFieldHandle;
210
249
 
211
- export { type ExpressionFieldHandle as E, type FieldLayout as F, type LanguageServiceOptions as L, type SegmenterOption as S, type UseExpressionFieldOptions as U, useLanguageService as a, useExpressionField as u };
250
+ export { type ExpressionFieldHandle as E, type FieldLayout as F, type LanguageServiceOptions as L, type SegmenterOption as S, type UseExpressionFieldOptions as U, type FieldFinish as a, useLanguageService as b, useExpressionField as u };
@@ -3,7 +3,7 @@ import { Extension } from '@codemirror/state';
3
3
  import { EditorView } from '@codemirror/view';
4
4
  import { CodeEditingOptions, GuttersOptions, LanguageServiceOptions as LanguageServiceOptions$1, TokenActionTarget, GotoDefinitionOptions } from '@tslite/codemirror';
5
5
  import { Segmenter, LanguageService, Token } from '@tslite/language-service';
6
- import { HostServiceOptions } from '@tslite/editor';
6
+ import { HostServiceOptions, HostServiceCodeOptions } from '@tslite/editor';
7
7
 
8
8
  /**
9
9
  * Onde, no texto, mora o código.
@@ -16,14 +16,16 @@ type SegmenterOption = "mustache" | "whole" | Segmenter;
16
16
  /** O que define o cérebro do campo. */
17
17
  interface LanguageServiceOptions {
18
18
  /**
19
- * O ambiente de tipos — o shape dos dados no escopo das expressões.
19
+ * O mundo em que o campo se tipa (`createWorld` do `@tslite/editor`): a lib da
20
+ * cópia do tsc, o `.d.ts` do `std` e as declarações do host. Os campos de uma
21
+ * tela dividem o mesmo mundo, e cada um é um arquivo virtual dele.
20
22
  *
21
- * **Memoize-o.** Um objeto novo a cada render reconstrói o serviço e joga
22
- * fora o cache de análise. `useMemo` no seu lado resolve.
23
+ * **Crie-o uma vez** (fora do render, ou num `useMemo`). Um mundo novo a cada
24
+ * render reconstrói o serviço e reparseia a lib.
23
25
  */
24
- readonly env?: HostServiceOptions["env"];
26
+ readonly world?: HostServiceOptions["world"];
25
27
  /**
26
- * Um serviço pronto, no lugar do `env`. Tem precedência — e é o caminho para
28
+ * Um serviço pronto, no lugar do `world`. Tem precedência — e é o caminho para
27
29
  * trocar o cérebro por outro (outra linguagem, outra implementação).
28
30
  */
29
31
  readonly service?: LanguageService;
@@ -53,19 +55,12 @@ interface LanguageServiceOptions {
53
55
  */
54
56
  readonly mode?: "expression" | "program" | "template";
55
57
  /**
56
- * Capability — **desinstala** features da Linguagem.
57
- *
58
- * Sem ela o campo só tipa, e uma atribuição (`{{ user.name = "ok" }}`) passa:
59
- * `=` existe na Linguagem completa. Não há padrão implícito aqui, porque qual
60
- * profile cabe num campo é decisão de produto.
58
+ * O tipo que o valor do campo tem de ter, como o texto de um tipo
59
+ * (`"boolean"`, `"Address"`): o campo acusa, enquanto se digita, o valor que
60
+ * não cabe nele. Vale para a expressão e para o template; um programa não tem
61
+ * valor. Sem ele, o campo aceita qualquer tipo.
61
62
  */
62
- readonly profile?: HostServiceOptions["profile"];
63
- /** Limites estruturais (anti-DoS). */
64
- readonly limits?: HostServiceOptions["limits"];
65
- /** Bindings nunca lidos. Ligado por padrão (é API de editor). */
66
- readonly unused?: HostServiceOptions["unused"];
67
- /** O formatador (`formatExpression` do `@tslite/format`). Sem ele, não formata. */
68
- readonly format?: HostServiceOptions["format"];
63
+ readonly type?: HostServiceOptions["type"];
69
64
  /**
70
65
  * O campo aceita ficar vazio: o texto vazio, ou só com espaços, é a ausência do
71
66
  * valor, e não o erro de "falta a expressão". Padrão: `false`. As sugestões no
@@ -73,10 +68,33 @@ interface LanguageServiceOptions {
73
68
  * (`createHostService({ optional })`).
74
69
  */
75
70
  readonly optional?: HostServiceOptions["optional"];
71
+ /**
72
+ * O perfil de capability do campo (o `@tslite/capability`): o que o campo pode
73
+ * escrever. O que ele recusa sai nos diagnósticos, enquanto se digita, sobre o
74
+ * texto que parseia (a E32 do `@tslite/editor`), com o veredito do executor e o da
75
+ * camada de controle. Sem padrão: sem ele, nada se poda (R18).
76
+ *
77
+ * **Crie-o uma vez**, como o `world`: um perfil novo a cada render reconstrói o
78
+ * serviço. No `mode: "template"`, ele julga o que o template desaçucara (o `map`
79
+ * de um `{% for %}`), como o executor, e a violação pousa na diretiva (a E34 do
80
+ * `@tslite/editor`). Com `service`, o perfil é de quem montou o serviço.
81
+ */
82
+ readonly profile?: HostServiceCodeOptions["profile"];
83
+ /**
84
+ * As regras a mais da camada de controle do `@tslite/behavior` (as de forma, as da
85
+ * aplicação), nos diagnósticos como as do perfil. Valem as mesmas regras do
86
+ * `profile`: crie-as uma vez.
87
+ */
88
+ readonly guards?: HostServiceCodeOptions["guards"];
76
89
  }
77
90
  /**
78
- * O `LanguageService` do campo. `null` quando não há `env` nem `service` — o
91
+ * O `LanguageService` do campo. `null` quando não há `world` nem `service` — o
79
92
  * editor continua editando texto, só sem inteligência.
93
+ *
94
+ * O serviço que o hook monta põe os arquivos virtuais do campo no mundo; quando
95
+ * ele é trocado (uma opção mudou) ou o campo desmonta, o hook os tira (o
96
+ * `dispose`, E28 do `@tslite/editor`). O `service` passado é de quem o montou, e
97
+ * o hook não o solta.
80
98
  */
81
99
  declare function useLanguageService(options: LanguageServiceOptions): LanguageService | null;
82
100
 
@@ -113,6 +131,20 @@ interface UseExpressionFieldOptions extends LanguageServiceOptions {
113
131
  * não é o autor terminando, e não commita.
114
132
  */
115
133
  readonly onCommit?: (text: string) => void;
134
+ /**
135
+ * O GESTO com que o autor terminou: o `Enter` que termina (layout `"grow"`), o
136
+ * `Escape` que cancela (layouts `"inline"` e `"grow"`) ou o foco que sai. Dispara
137
+ * também quando nada mudou, com `dirty` dizendo se havia rascunho diferente do
138
+ * `value` naquele instante (R19).
139
+ *
140
+ * No `Enter` e no blur, ele vem depois do `onCommit` (quando há o que commitar):
141
+ * quem recusa o texto no `onCommit` já recusou quando o gesto chega. O `Escape`
142
+ * volta o rascunho ao `value`, sem `onChange` nem `onCommit`, e avisa. A tecla
143
+ * que a lista de sugestões consome (o `Enter` que aceita, o `Escape` que fecha)
144
+ * não é o autor terminando, e não dispara. Sem esta função, o `Escape` não é do
145
+ * campo.
146
+ */
147
+ readonly onFinish?: (finish: FieldFinish) => void;
116
148
  /** Como o campo se apresenta. Padrão: `"inline"`. */
117
149
  readonly layout?: FieldLayout;
118
150
  /**
@@ -193,6 +225,13 @@ interface UseExpressionFieldOptions extends LanguageServiceOptions {
193
225
  /** Extensões extras do CodeMirror — a escotilha de fuga. */
194
226
  readonly extensions?: readonly Extension[];
195
227
  }
228
+ /** Como o autor terminou a edição do campo (R19). */
229
+ interface FieldFinish {
230
+ /** O gesto: o `Enter` que termina, o `Escape` que cancela, ou o foco que sai. */
231
+ readonly via: "enter" | "escape" | "blur";
232
+ /** Havia rascunho diferente do `value` quando o autor terminou. */
233
+ readonly dirty: boolean;
234
+ }
196
235
  /** O que o hook devolve. */
197
236
  interface ExpressionFieldHandle {
198
237
  /** Ponha num elemento vazio: é onde o editor monta. */
@@ -208,4 +247,4 @@ interface ExpressionFieldHandle {
208
247
  }
209
248
  declare function useExpressionField(options: UseExpressionFieldOptions): ExpressionFieldHandle;
210
249
 
211
- export { type ExpressionFieldHandle as E, type FieldLayout as F, type LanguageServiceOptions as L, type SegmenterOption as S, type UseExpressionFieldOptions as U, useLanguageService as a, useExpressionField as u };
250
+ export { type ExpressionFieldHandle as E, type FieldLayout as F, type LanguageServiceOptions as L, type SegmenterOption as S, type UseExpressionFieldOptions as U, type FieldFinish as a, useLanguageService as b, useExpressionField as u };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tslite/react",
3
- "version": "1.3.0",
4
- "description": "React bindings for TSLite — a headless expression field (CodeMirror 6) with type-aware highlighting, completion, diagnostics and quick-fixes, driven by the TSLite checker.",
3
+ "version": "1.5.0",
4
+ "description": "React bindings for TSLite — a headless expression field (CodeMirror 6) with type-aware highlighting, completion, diagnostics and quick-fixes, driven by the TypeScript language service ported to TSLite.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -48,8 +48,7 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@tslite/codemirror": "^1.3.0",
51
- "@tslite/editor": "^1.4.1",
52
- "@tslite/format": "^1.4.0",
51
+ "@tslite/editor": "^1.7.0",
53
52
  "@tslite/language-service": "^1.2.0"
54
53
  },
55
54
  "peerDependencies": {
@@ -61,8 +60,7 @@
61
60
  "@codemirror/state": "^6.0.0",
62
61
  "@codemirror/view": "^6.37.0",
63
62
  "react": ">=18",
64
- "react-dom": ">=18",
65
- "@tslite/checker": "^1.8.0"
63
+ "react-dom": ">=18"
66
64
  },
67
65
  "devDependencies": {
68
66
  "@codemirror/autocomplete": "^6.20.3",
@@ -77,7 +75,8 @@
77
75
  "@types/react-dom": "^18.3.1",
78
76
  "react": "^18.3.1",
79
77
  "react-dom": "^18.3.1",
80
- "@tslite/checker": "1.8.0"
78
+ "@tslite/checker": "1.13.0",
79
+ "@tslite/std": "1.4.0"
81
80
  },
82
81
  "peerDependenciesMeta": {
83
82
  "@codemirror/search": {