llm-testrunner-components 1.2.3 → 1.2.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.
Files changed (78) hide show
  1. package/dist/cjs/{app-chips_4.cjs.entry.js → app-chips_5.cjs.entry.js} +38 -6
  2. package/dist/cjs/app-chips_5.cjs.entry.js.map +1 -0
  3. package/dist/cjs/index.cjs.js +40 -7
  4. package/dist/cjs/index.cjs.js.map +1 -1
  5. package/dist/cjs/llm-testrunner.cjs.js +1 -1
  6. package/dist/cjs/loader.cjs.js +1 -1
  7. package/dist/collection/collection-manifest.json +1 -0
  8. package/dist/collection/components/llm-test-runner/llm-test-runner.import-export.test.js +22 -12
  9. package/dist/collection/components/llm-test-runner/llm-test-runner.import-export.test.js.map +1 -1
  10. package/dist/collection/components/llm-test-runner/llm-test-runner.js +17 -6
  11. package/dist/collection/components/llm-test-runner/llm-test-runner.js.map +1 -1
  12. package/dist/collection/components/llm-test-runner/test-cases/chat-history.css +101 -0
  13. package/dist/collection/components/llm-test-runner/test-cases/chat-history.js +105 -0
  14. package/dist/collection/components/llm-test-runner/test-cases/chat-history.js.map +1 -0
  15. package/dist/collection/components/llm-test-runner/test-cases/llm-test-case-row.js +12 -2
  16. package/dist/collection/components/llm-test-runner/test-cases/llm-test-case-row.js.map +1 -1
  17. package/dist/collection/components/llm-test-runner/test-cases/llm-test-cases.js +2 -2
  18. package/dist/collection/components/llm-test-runner/test-cases/llm-test-cases.js.map +1 -1
  19. package/dist/collection/index.js.map +1 -1
  20. package/dist/collection/lib/form/components/app-chips.js +1 -1
  21. package/dist/collection/lib/form/components/app-select.js +1 -1
  22. package/dist/collection/lib/form/components/app-textarea.js +2 -2
  23. package/dist/collection/lib/import-export/test-suite-exporter.js +4 -0
  24. package/dist/collection/lib/import-export/test-suite-exporter.js.map +1 -1
  25. package/dist/collection/lib/test-cases/test-case-factory.js +2 -0
  26. package/dist/collection/lib/test-cases/test-case-factory.js.map +1 -1
  27. package/dist/collection/schemas/test-case.js +6 -0
  28. package/dist/collection/schemas/test-case.js.map +1 -1
  29. package/dist/collection/types/llm-test-runner.js.map +1 -1
  30. package/dist/collection/types/test-case.js.map +1 -1
  31. package/dist/components/app-chips.js +1 -1
  32. package/dist/components/app-select.js +1 -1
  33. package/dist/components/app-textarea.js +1 -1
  34. package/dist/components/chat-history.d.ts +11 -0
  35. package/dist/components/chat-history.js +2 -0
  36. package/dist/components/chat-history.js.map +1 -0
  37. package/dist/components/index.js +1 -1
  38. package/dist/components/llm-test-runner.js +1 -1
  39. package/dist/components/{p-BcygfrMf.js → p-B87Lt3z4.js} +3 -3
  40. package/dist/components/p-B87Lt3z4.js.map +1 -0
  41. package/dist/components/p-Bx2jqguC.js +2 -0
  42. package/dist/components/p-Bx2jqguC.js.map +1 -0
  43. package/dist/components/{p-CVtKFBJl.js → p-D2qDAxFN.js} +2 -2
  44. package/dist/components/{p-Dv7cB5FU.js → p-D4dHUFN9.js} +2 -2
  45. package/dist/components/{p-CE5-1jfZ.js → p-eN2dLrsr.js} +2 -2
  46. package/dist/esm/{app-chips_4.entry.js → app-chips_5.entry.js} +38 -7
  47. package/dist/esm/app-chips_5.entry.js.map +1 -0
  48. package/dist/esm/index.js +40 -7
  49. package/dist/esm/index.js.map +1 -1
  50. package/dist/esm/llm-testrunner.js +1 -1
  51. package/dist/esm/loader.js +1 -1
  52. package/dist/llm-testrunner/index.esm.js +2 -2
  53. package/dist/llm-testrunner/index.esm.js.map +1 -1
  54. package/dist/llm-testrunner/llm-testrunner.esm.js +1 -1
  55. package/dist/llm-testrunner/p-21202f12.entry.js +2 -0
  56. package/dist/llm-testrunner/p-21202f12.entry.js.map +1 -0
  57. package/dist/react/components.d.ts +6 -1
  58. package/dist/react/components.d.ts.map +1 -1
  59. package/dist/react/components.js +9 -0
  60. package/dist/types/components/llm-test-runner/llm-test-runner.d.ts +1 -0
  61. package/dist/types/components/llm-test-runner/test-cases/chat-history.d.ts +14 -0
  62. package/dist/types/components/llm-test-runner/test-cases/llm-test-case-row.d.ts +5 -0
  63. package/dist/types/components/llm-test-runner/test-cases/llm-test-cases.d.ts +2 -0
  64. package/dist/types/components.d.ts +51 -0
  65. package/dist/types/index.d.ts +1 -1
  66. package/dist/types/lib/import-export/test-suite-exporter.d.ts +4 -0
  67. package/dist/types/schemas/test-case.d.ts +17 -0
  68. package/dist/types/types/llm-test-runner.d.ts +2 -1
  69. package/dist/types/types/test-case.d.ts +1 -1
  70. package/package.json +1 -1
  71. package/dist/cjs/app-chips_4.cjs.entry.js.map +0 -1
  72. package/dist/components/p-BcygfrMf.js.map +0 -1
  73. package/dist/esm/app-chips_4.entry.js.map +0 -1
  74. package/dist/llm-testrunner/p-5df053b4.entry.js +0 -2
  75. package/dist/llm-testrunner/p-5df053b4.entry.js.map +0 -1
  76. /package/dist/components/{p-CVtKFBJl.js.map → p-D2qDAxFN.js.map} +0 -0
  77. /package/dist/components/{p-Dv7cB5FU.js.map → p-D4dHUFN9.js.map} +0 -0
  78. /package/dist/components/{p-CE5-1jfZ.js.map → p-eN2dLrsr.js.map} +0 -0
@@ -1,2 +1,2 @@
1
- import{p as e,b as t}from"./p-DxzhGhec.js";export{s as setNonce}from"./p-DxzhGhec.js";import{g as a}from"./p-GQwFOmwJ.js";var r=()=>{const s=import.meta.url;const t={};if(s!==""){t.resourcesUrl=new URL(".",s).href}return e(t)};r().then((async e=>{await a();return t([["p-5df053b4",[[513,"llm-test-runner",{delayMs:[2,"delay-ms"],useSave:[4,"use-save"],usePromptEditor:[4,"use-prompt-editor"],resolveExpectedOutcome:[16],initialTestCases:[16],defaultExpectedOutcomeSchema:[16],testCases:[32],isRunningAll:[32],error:[32],isExportingTestSuite:[32],isExportingTestResults:[32],isSaving:[32],resetSavingState:[64],getTestCases:[64]}],[513,"app-chips",{value:[16],config:[16]}],[513,"app-select",{value:[1],config:[16]}],[513,"app-textarea",{value:[1],config:[16]}]]]],e)}));
1
+ import{p as e,b as t}from"./p-DxzhGhec.js";export{s as setNonce}from"./p-DxzhGhec.js";import{g as a}from"./p-GQwFOmwJ.js";var r=()=>{const t=import.meta.url;const s={};if(t!==""){s.resourcesUrl=new URL(".",t).href}return e(s)};r().then((async e=>{await a();return t([["p-21202f12",[[513,"llm-test-runner",{delayMs:[2,"delay-ms"],useSave:[4,"use-save"],usePromptEditor:[4,"use-prompt-editor"],resolveExpectedOutcome:[16],initialTestCases:[16],defaultExpectedOutcomeSchema:[16],testCases:[32],isRunningAll:[32],error:[32],isExportingTestSuite:[32],isExportingTestResults:[32],isSaving:[32],resetSavingState:[64],getTestCases:[64]}],[513,"app-chips",{value:[16],config:[16]}],[513,"app-select",{value:[1],config:[16]}],[513,"app-textarea",{value:[1],config:[16]}],[513,"chat-history",{chatHistoryEnabled:[4,"chat-history-enabled"],chatHistoryValue:[1,"chat-history-value"]}]]]],e)}));
2
2
  //# sourceMappingURL=llm-testrunner.esm.js.map
@@ -0,0 +1,2 @@
1
+ import{r as e,c as a,h as r}from"./p-DxzhGhec.js";export{LLMTestRunner as llm_test_runner}from"./index.esm.js";const t=()=>`.app-chips{margin-bottom:var(--spacing-4)}.app-chips__label{display:block;margin-bottom:var(--spacing-2);font-weight:var(--font-weight-medium);color:var(--foreground);font-size:var(--font-size-sm)}.app-chips__container{display:flex;flex-wrap:wrap;gap:var(--spacing-2);align-items:center}.app-chips__chip{display:inline-flex;align-items:center;gap:var(--spacing-2);padding:var(--spacing-1) var(--spacing-2);font-size:var(--font-size-xs);font-weight:var(--font-weight-medium);border-radius:var(--radius-md);background:var(--accent);border:var(--border-width) solid var(--border)}.app-chips__chip:not(:has(a)){background:var(--info);color:var(--info-foreground);border:none;border-radius:var(--radius-2xl)}.app-chips__link{color:var(--info);text-decoration:none;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.app-chips__link:hover{text-decoration:underline}.app-chips__remove{background:none;border:none;cursor:pointer;font-size:var(--font-size-xs);padding:0;width:var(--spacing-4);height:var(--spacing-4);display:flex;align-items:center;justify-content:center;border-radius:var(--radius-full);color:var(--muted-foreground);opacity:var(--opacity-muted)}.app-chips__chip:not(:has(a)) .app-chips__remove{color:var(--info-foreground);opacity:var(--opacity-hover)}.app-chips__remove:hover{opacity:1;background:var(--muted)}.app-chips__chip:not(:has(a)) .app-chips__remove:hover{background:rgba(255, 255, 255, 0.2)}.app-chips__input{border:var(--border-width) solid var(--input);border-radius:var(--radius-md);padding:var(--spacing-2);font-size:var(--font-size-xs);outline:none;min-width:120px;background:var(--background);color:var(--foreground)}.app-chips__input:focus{border-color:var(--ring);box-shadow:0 0 0 2px rgba(59, 130, 246, 0.1)}`;const o=class{constructor(r){e(this,r);this.addChip=a(this,"addChip");this.removeChip=a(this,"removeChip")}value=[];config;addChip;removeChip;emitAddChip(e){this.addChip.emit({value:e})}emitRemoveChip(e){this.removeChip.emit({value:e})}hasDuplicateChip(e){const a=e.trim().toLowerCase();return this.value.some((e=>e.trim().toLowerCase()===a))}render(){const e=this.config;const a={placeholder:e.placeholder,required:e.required,disabled:e.disabled,readOnly:e.readOnly,id:e.name,name:e.name,autocomplete:e.autocomplete};return r("div",{key:"fb7d4d5444e9c9ac33c56aec88e3e10ed103c8be",class:"app-chips"},e.label&&r("label",{key:"2d0041b3a137fecddef2273eac3792b5e8de27ab",class:"app-chips__label",htmlFor:e.name},e.label),r("div",{key:"f73b1105e567b233626073e05b9da712689e7b12",class:"app-chips__container"},this.value.map((a=>r("span",{class:"app-chips__chip",key:a},e.type==="url"?r("a",{href:a,target:"_blank",rel:"noopener noreferrer",class:"app-chips__link"},a):a,r("button",{class:"app-chips__remove",type:"button",onClick:()=>this.emitRemoveChip(a)},"×")))),r("input",{key:"7676ff95531b34d10cbf9402e72a723e7e123e0e",class:"app-chips__input",type:e.type||"text",...a,onKeyDown:e=>{if(e.key==="Enter"){const a=e.target;const r=a.value.trim();if(!r)return;if(this.hasDuplicateChip(r)){a.value="";return}this.emitAddChip(r);a.value=""}}})))}};o.style=t();const i=()=>`.app-select{margin-bottom:var(--spacing-4)}.app-select__label{display:block;margin-bottom:var(--spacing-2);font-weight:var(--font-weight-medium);color:var(--foreground);font-size:var(--font-size-sm)}.app-select__select{border:var(--border-width) solid var(--input);border-radius:var(--radius-md);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);padding:var(--spacing-1) var(--spacing-2);outline:none;background:var(--background);width:145px;color:var(--foreground)}.app-select__select:focus{border-color:var(--ring);box-shadow:0 0 0 2px rgba(59, 130, 246, 0.1)}`;const s=class{constructor(r){e(this,r);this.valueChange=a(this,"valueChange")}value;config;valueChange;render(){const e=this.config;const a={id:e.name,name:e.name,disabled:e.disabled,required:e.required,readOnly:e.readOnly,placeholder:e.placeholder,autocomplete:e.autocomplete};return r("div",{key:"968f0fffe1eff976ac7e00f02db6fb84aa529de4",class:"app-select"},e.label&&r("label",{key:"dac02d2335754ff5d6ce6ba1df5777f8b019cfae",class:"app-select__label",htmlFor:e.name},e.label),r("div",{key:"c92698199479bbdde1cfd559d69fc97e54d2862a"},r("select",{key:"6e9b27b034d057921f52fbd12653c5ef1b6af1bc",...a,class:"app-select__select",onInput:a=>{const r=a.target.value;const t=e.optionList.find((e=>String(e)===r));this.valueChange.emit({value:t!==undefined?t:r})}},e.optionList?.map((e=>r("option",{value:String(e),key:String(e),selected:this.value===e},String(e)))))))}};s.style=i();const n=()=>`.textarea-wrapper{margin-bottom:var(--spacing-4)}.textarea-label{display:block;margin-bottom:var(--spacing-2);font-weight:var(--font-weight-medium);color:var(--foreground);font-size:var(--font-size-sm)}.textarea-element{width:95%;box-sizing:border-box;padding:var(--spacing-3);border:2px solid var(--input);border-radius:var(--radius);font-size:var(--font-size-sm);resize:vertical;outline:none;transition:border-color 0.2s ease;font-family:inherit;background:var(--background);color:var(--foreground)}.textarea-element:focus{border-color:var(--ring);box-shadow:0 0 0 3px rgba(59, 130, 246, 0.1)}.textarea-wrapper--read-only .textarea-label{color:var(--muted-foreground)}.textarea-element:read-only{background:var(--muted);color:var(--muted-foreground);border-color:var(--border);cursor:not-allowed;resize:none}.textarea-element:read-only:focus{border-color:var(--border);box-shadow:none}.help-text{margin-top:var(--spacing-1);font-size:var(--font-size-xs);color:var(--muted-foreground, #6b7280);line-height:1.4}`;const c=class{constructor(r){e(this,r);this.valueChange=a(this,"valueChange")}value;config;valueChange;handleChange=e=>{const a=e.target;this.valueChange.emit({value:a.value})};render(){const e=this.config;const a={placeholder:e.placeholder,required:e.required,disabled:e.disabled,readOnly:e.readOnly,rows:e.rows,id:e.name,name:e.name,autocomplete:e.autocomplete};return r("div",{key:"f0749b1f2badf8434272da9fb37b354b42ba988b",class:{"textarea-wrapper":true,"textarea-wrapper--read-only":!!e.readOnly}},e.label&&r("label",{key:"3448c838bcf9e962df005eae8fc313d216497c35",class:"textarea-label",htmlFor:e.name},e.label),r("textarea",{key:"b4ee67a24fa71b0fa042625f943b0e226a6d14b7",...a,class:"textarea-element",value:this.value,onInput:this.handleChange}),e.helpText&&r("p",{key:"fb6263c32e6cc5e36dbc77344c31487d63d51a1c",class:"help-text"},e.helpText))}};c.style=n();const d=()=>`.chat-history{display:flex;flex-direction:column;gap:var(--spacing-3);margin-top:var(--spacing-4)}.chat-history__toggle-row{display:flex;align-items:center}.chat-history__switch{position:relative;display:inline-flex;align-items:center;gap:var(--spacing-3);cursor:pointer;user-select:none}.chat-history__switch-input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0}.chat-history__switch-ui{position:relative;flex-shrink:0;width:2.75rem;height:1.5rem;border-radius:var(--radius-full);background:var(--muted);border:var(--border-width) solid var(--border);transition:background 0.15s ease, border-color 0.15s ease}@media (prefers-reduced-motion: reduce){.chat-history__switch-ui,.chat-history__switch-thumb{transition:none}}.chat-history__switch-thumb{position:absolute;top:2px;left:2px;width:calc(1.5rem - 6px);height:calc(1.5rem - 6px);border-radius:var(--radius-full);background:var(--background);box-shadow:var(--shadow-sm);transition:transform 0.15s ease}.chat-history__switch-input:checked+.chat-history__switch-ui{background:var(--primary);border-color:var(--primary)}.chat-history__switch-input:checked+.chat-history__switch-ui .chat-history__switch-thumb{transform:translateX(calc(2.75rem - (1.5rem - 6px) - 4px))}.chat-history__switch-input:focus-visible+.chat-history__switch-ui{outline:2px solid var(--ring);outline-offset:2px}.chat-history__switch-text{font-size:var(--font-size-sm, 0.875rem);color:var(--foreground)}.chat-history__textarea{width:100%;box-sizing:border-box;padding:var(--spacing-2) var(--spacing-3);border:var(--border-width) solid var(--border);border-radius:var(--radius-md);font:inherit;resize:vertical;min-height:9rem;background:var(--background)}.chat-history__textarea:focus-visible{outline:2px solid var(--ring);outline-offset:2px}`;const h=`[\n {"role": "user", "content": "How do I import a saved suite?"},\n {"role": "model", "content": "Use Import and pick the JSON from Export suite."}\n]`;const p=class{constructor(r){e(this,r);this.chatHistoryChange=a(this,"chatHistoryChange")}chatHistoryEnabled=false;chatHistoryValue="";chatHistoryChange;emit(e){this.chatHistoryChange.emit(e)}onToggle=e=>{const a=e.target.checked;this.emit({enabled:a,value:this.chatHistoryValue})};onTextInput=e=>{const a=e.target.value;this.emit({enabled:this.chatHistoryEnabled,value:a})};render(){return r("div",{key:"f444a4b5bd9b48df151cad67b54bef54116d11b3",class:"chat-history"},r("div",{key:"7216d764fb905ac5e8e33209d9586525e59fa218",class:"chat-history__toggle-row"},r("label",{key:"d5d092c323b48543c96525d449bcb03dcaf5113b",class:"chat-history__switch"},r("input",{key:"5104ce460686434156454fc1dfd3685ba0e0968c",type:"checkbox",class:"chat-history__switch-input",checked:this.chatHistoryEnabled,onInput:this.onToggle}),r("span",{key:"fa2e51bce0d6ff2d3bf133383e1ce940521097b0",class:"chat-history__switch-ui","aria-hidden":"true"},r("span",{key:"e0d897ca166623ece09834b44b5baa12605cb9f3",class:"chat-history__switch-thumb"})),r("span",{key:"e769678fde5d670e634d7a8e905ef09ce936f440",class:"chat-history__switch-text"},"Chat history"))),this.chatHistoryEnabled?r("textarea",{class:"chat-history__textarea",value:this.chatHistoryValue,rows:8,placeholder:h,"aria-label":"Chat history",onInput:this.onTextInput}):null)}};p.style=d();export{o as app_chips,s as app_select,c as app_textarea,p as chat_history};
2
+ //# sourceMappingURL=p-21202f12.entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["appChipsCss","AppChips","value","config","addChip","removeChip","emitAddChip","val","this","emit","emitRemoveChip","hasDuplicateChip","normalized","trim","toLowerCase","some","chip","render","c","allowedAttrs","placeholder","required","disabled","readOnly","id","name","autocomplete","h","key","class","label","htmlFor","map","type","href","target","rel","onClick","onKeyDown","e","input","appSelectCss","AppSelect","valueChange","onInput","raw","matched","optionList","find","opt","String","undefined","option","selected","appTextareaCss","AppTextarea","handleChange","rows","helpText","chatHistoryCss","CHAT_HISTORY_PLACEHOLDER","ChatHistory","chatHistoryEnabled","chatHistoryValue","chatHistoryChange","detail","onToggle","checked","enabled","onTextInput"],"sources":["src/lib/form/components/app-chips.css?tag=app-chips&encapsulation=shadow","src/lib/form/components/app-chips.tsx","src/lib/form/components/app-select.css?tag=app-select&encapsulation=shadow","src/lib/form/components/app-select.tsx","src/lib/form/components/app-textarea.css?tag=app-textarea&encapsulation=shadow","src/lib/form/components/app-textarea.tsx","src/components/llm-test-runner/test-cases/chat-history.css?tag=chat-history&encapsulation=shadow","src/components/llm-test-runner/test-cases/chat-history.tsx"],"sourcesContent":[".app-chips {\n margin-bottom: var(--spacing-4);\n}\n\n.app-chips__label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.app-chips__container {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-2);\n align-items: center;\n}\n\n.app-chips__chip {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2);\n padding: var(--spacing-1) var(--spacing-2);\n font-size: var(--font-size-xs);\n font-weight: var(--font-weight-medium);\n border-radius: var(--radius-md);\n background: var(--accent);\n border: var(--border-width) solid var(--border);\n}\n\n/* Keyword-style chip override (non-URL chips) */\n.app-chips__chip:not(:has(a)) {\n background: var(--info);\n color: var(--info-foreground);\n border: none;\n border-radius: var(--radius-2xl);\n}\n\n.app-chips__link {\n color: var(--info);\n text-decoration: none;\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.app-chips__link:hover {\n text-decoration: underline;\n}\n\n.app-chips__remove {\n background: none;\n border: none;\n cursor: pointer;\n font-size: var(--font-size-xs);\n padding: 0;\n width: var(--spacing-4);\n height: var(--spacing-4);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--radius-full);\n color: var(--muted-foreground);\n opacity: var(--opacity-muted);\n}\n\n.app-chips__chip:not(:has(a)) .app-chips__remove {\n color: var(--info-foreground);\n opacity: var(--opacity-hover);\n}\n\n.app-chips__remove:hover {\n opacity: 1;\n background: var(--muted);\n}\n\n.app-chips__chip:not(:has(a)) .app-chips__remove:hover {\n background: rgba(255, 255, 255, 0.2);\n}\n\n.app-chips__input {\n border: var(--border-width) solid var(--input);\n border-radius: var(--radius-md);\n padding: var(--spacing-2);\n font-size: var(--font-size-xs);\n outline: none;\n min-width: 120px;\n background: var(--background);\n color: var(--foreground);\n}\n\n.app-chips__input:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n","import { Component, Prop, h, Event, EventEmitter } from '@stencil/core';\nimport { ChipsConfig } from '../schema';\n\n@Component({\n tag: 'app-chips',\n styleUrl: 'app-chips.css',\n shadow: true,\n})\nexport class AppChips {\n @Prop() value: string[] = [];\n @Prop() config: ChipsConfig;\n\n @Event() addChip: EventEmitter<{ value: string }>;\n\n @Event() removeChip: EventEmitter<{ value: string }>;\n\n private emitAddChip(val: string) {\n this.addChip.emit({\n value: val,\n });\n }\n\n private emitRemoveChip(value: string) {\n this.removeChip.emit({\n value,\n });\n }\n\n private hasDuplicateChip(value: string): boolean {\n const normalized = value.trim().toLowerCase();\n return this.value.some(chip => chip.trim().toLowerCase() === normalized);\n }\n\n render() {\n const c = this.config;\n\n const allowedAttrs = {\n placeholder: c.placeholder,\n required: c.required,\n disabled: c.disabled,\n readOnly: c.readOnly,\n id: c.name,\n name: c.name,\n autocomplete: c.autocomplete,\n };\n\n return (\n <div class=\"app-chips\">\n {c.label && (\n <label class=\"app-chips__label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <div class=\"app-chips__container\">\n {this.value.map((chip) => (\n <span class=\"app-chips__chip\" key={chip}>\n {c.type === 'url' ? (\n <a\n href={chip}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"app-chips__link\"\n >\n {chip}\n </a>\n ) : (\n chip\n )}\n\n <button\n class=\"app-chips__remove\"\n type=\"button\"\n onClick={() => this.emitRemoveChip(chip)}\n >\n ×\n </button>\n </span>\n ))}\n\n <input\n class=\"app-chips__input\"\n type={c.type || 'text'}\n {...allowedAttrs}\n onKeyDown={(e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n const input = e.target as HTMLInputElement;\n const val = input.value.trim();\n if (!val) return;\n if (this.hasDuplicateChip(val)) {\n input.value = '';\n return;\n }\n\n this.emitAddChip(val);\n input.value = '';\n }\n }}\n />\n </div>\n </div>\n );\n }\n}\n",".app-select {\n margin-bottom: var(--spacing-4);\n}\n\n.app-select__label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.app-select__select {\n border: var(--border-width) solid var(--input);\n border-radius: var(--radius-md);\n font-size: var(--font-size-sm);\n font-weight: var(--font-weight-medium);\n padding: var(--spacing-1) var(--spacing-2);\n outline: none;\n background: var(--background);\n width: 145px;\n color: var(--foreground);\n}\n\n.app-select__select:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\nimport { SelectConfig } from '../schema';\n\n@Component({\n tag: 'app-select',\n styleUrl: 'app-select.css',\n shadow: true,\n})\nexport class AppSelect {\n @Prop() value: string;\n @Prop() config: SelectConfig;\n @Event() valueChange: EventEmitter<{ value: string }>;\n\n render() {\n const c = this.config;\n const allowedAttrs = {\n id: c.name,\n name: c.name,\n disabled: c.disabled,\n required: c.required,\n readOnly: c.readOnly,\n placeholder: c.placeholder,\n autocomplete: c.autocomplete,\n };\n return (\n <div class=\"app-select\">\n {c.label && (\n <label class=\"app-select__label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <div>\n <select\n {...allowedAttrs}\n class=\"app-select__select\"\n onInput={(e: Event) => {\n const raw = (e.target as HTMLSelectElement).value;\n const matched = c.optionList.find(opt => String(opt) === raw);\n this.valueChange.emit({\n value: matched !== undefined ? matched : raw,\n });\n }}\n >\n {c.optionList?.map(option => (\n <option\n value={String(option)}\n key={String(option)}\n selected={this.value === option}\n >\n {String(option)}\n </option>\n ))}\n </select>\n </div>\n </div>\n );\n }\n}\n",".textarea-wrapper {\n margin-bottom: var(--spacing-4);\n}\n\n.textarea-label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.textarea-element {\n width: 95%;\n box-sizing: border-box;\n padding: var(--spacing-3);\n border: 2px solid var(--input);\n border-radius: var(--radius);\n font-size: var(--font-size-sm);\n resize: vertical;\n outline: none;\n transition: border-color 0.2s ease;\n font-family: inherit;\n background: var(--background);\n color: var(--foreground);\n}\n\n.textarea-element:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.textarea-wrapper--read-only .textarea-label {\n color: var(--muted-foreground);\n}\n\n.textarea-element:read-only {\n background: var(--muted);\n color: var(--muted-foreground);\n border-color: var(--border);\n cursor: not-allowed;\n resize: none;\n}\n\n.textarea-element:read-only:focus {\n border-color: var(--border);\n box-shadow: none;\n}\n\n.help-text {\n margin-top: var(--spacing-1);\n font-size: var(--font-size-xs);\n color: var(--muted-foreground, #6b7280);\n line-height: 1.4;\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\nimport { TextAreaConfig } from '../schema';\n\n@Component({\n tag: 'app-textarea',\n styleUrl: 'app-textarea.css',\n shadow: true,\n})\nexport class AppTextarea {\n @Prop() value: string;\n @Prop() config: TextAreaConfig;\n\n @Event() valueChange: EventEmitter<{ value: string }>;\n\n private handleChange = (e: Event) => {\n const target = e.target as HTMLTextAreaElement;\n\n this.valueChange.emit({\n value: target.value,\n });\n };\n\n render() {\n const c = this.config;\n\n const allowedAttrs = {\n placeholder: c.placeholder,\n required: c.required,\n disabled: c.disabled,\n readOnly: c.readOnly,\n rows: c.rows,\n id: c.name,\n name: c.name,\n autocomplete: c.autocomplete,\n };\n\n return (\n <div\n class={{\n 'textarea-wrapper': true,\n 'textarea-wrapper--read-only': !!c.readOnly,\n }}\n >\n {c.label && (\n <label class=\"textarea-label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <textarea\n {...allowedAttrs}\n class=\"textarea-element\"\n value={this.value}\n onInput={this.handleChange}\n ></textarea>\n\n {c.helpText && <p class=\"help-text\">{c.helpText}</p>}\n </div>\n );\n }\n}\n",".chat-history {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-3);\n margin-top: var(--spacing-4);\n}\n\n.chat-history__toggle-row {\n display: flex;\n align-items: center;\n}\n\n.chat-history__switch {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-3);\n cursor: pointer;\n user-select: none;\n}\n\n.chat-history__switch-input {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n.chat-history__switch-ui {\n position: relative;\n flex-shrink: 0;\n width: 2.75rem;\n height: 1.5rem;\n border-radius: var(--radius-full);\n background: var(--muted);\n border: var(--border-width) solid var(--border);\n transition:\n background 0.15s ease,\n border-color 0.15s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .chat-history__switch-ui,\n .chat-history__switch-thumb {\n transition: none;\n }\n}\n\n.chat-history__switch-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: calc(1.5rem - 6px);\n height: calc(1.5rem - 6px);\n border-radius: var(--radius-full);\n background: var(--background);\n box-shadow: var(--shadow-sm);\n transition: transform 0.15s ease;\n}\n\n.chat-history__switch-input:checked + .chat-history__switch-ui {\n background: var(--primary);\n border-color: var(--primary);\n}\n\n.chat-history__switch-input:checked + .chat-history__switch-ui .chat-history__switch-thumb {\n /* track width − end padding (2px × 2) − thumb width */\n transform: translateX(calc(2.75rem - (1.5rem - 6px) - 4px));\n}\n\n.chat-history__switch-input:focus-visible + .chat-history__switch-ui {\n outline: 2px solid var(--ring);\n outline-offset: 2px;\n}\n\n.chat-history__switch-text {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--foreground);\n}\n\n.chat-history__textarea {\n width: 100%;\n box-sizing: border-box;\n padding: var(--spacing-2) var(--spacing-3);\n border: var(--border-width) solid var(--border);\n border-radius: var(--radius-md);\n font: inherit;\n resize: vertical;\n min-height: 9rem;\n background: var(--background);\n}\n\n.chat-history__textarea:focus-visible {\n outline: 2px solid var(--ring);\n outline-offset: 2px;\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\n\nconst CHAT_HISTORY_PLACEHOLDER = `[\n {\"role\": \"user\", \"content\": \"How do I import a saved suite?\"},\n {\"role\": \"model\", \"content\": \"Use Import and pick the JSON from Export suite.\"}\n]`;\n\nexport type ChatHistoryChangeDetail = {\n enabled: boolean;\n value: string;\n};\n\n@Component({\n tag: 'chat-history',\n styleUrl: 'chat-history.css',\n shadow: true,\n})\nexport class ChatHistory {\n @Prop() chatHistoryEnabled = false;\n @Prop() chatHistoryValue = '';\n\n @Event({ bubbles: true, composed: true })\n chatHistoryChange: EventEmitter<ChatHistoryChangeDetail>;\n\n private emit(detail: ChatHistoryChangeDetail) {\n this.chatHistoryChange.emit(detail);\n }\n\n private onToggle = (e: Event) => {\n const checked = (e.target as HTMLInputElement).checked;\n this.emit({ enabled: checked, value: this.chatHistoryValue });\n };\n\n private onTextInput = (e: Event) => {\n const value = (e.target as HTMLTextAreaElement).value;\n this.emit({ enabled: this.chatHistoryEnabled, value });\n };\n\n render() {\n return (\n <div class=\"chat-history\">\n <div class=\"chat-history__toggle-row\">\n <label class=\"chat-history__switch\">\n <input\n type=\"checkbox\"\n class=\"chat-history__switch-input\"\n checked={this.chatHistoryEnabled}\n onInput={this.onToggle}\n />\n <span class=\"chat-history__switch-ui\" aria-hidden=\"true\">\n <span class=\"chat-history__switch-thumb\" />\n </span>\n <span class=\"chat-history__switch-text\">Chat history</span>\n </label>\n </div>\n {this.chatHistoryEnabled ? (\n <textarea\n class=\"chat-history__textarea\"\n value={this.chatHistoryValue}\n rows={8}\n placeholder={CHAT_HISTORY_PLACEHOLDER}\n aria-label=\"Chat history\"\n onInput={this.onTextInput}\n />\n ) : null}\n </div>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -3,10 +3,11 @@
3
3
  * Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
4
4
  */
5
5
  import type { EventName, StencilReactComponent } from '@stencil/react-output-target/runtime';
6
- import { type AppChipsCustomEvent, type AppSelectCustomEvent, type AppTextareaCustomEvent, type LLMRequestPayload, type LlmTestRunnerCustomEvent, type SavePayload } from "llm-testrunner-components";
6
+ import { type AppChipsCustomEvent, type AppSelectCustomEvent, type AppTextareaCustomEvent, type ChatHistoryChangeDetail, type ChatHistoryCustomEvent, type LLMRequestPayload, type LlmTestRunnerCustomEvent, type SavePayload } from "llm-testrunner-components";
7
7
  import { AppChips as AppChipsElement } from "llm-testrunner-components/./dist/components/app-chips.js";
8
8
  import { AppSelect as AppSelectElement } from "llm-testrunner-components/./dist/components/app-select.js";
9
9
  import { AppTextarea as AppTextareaElement } from "llm-testrunner-components/./dist/components/app-textarea.js";
10
+ import { ChatHistory as ChatHistoryElement } from "llm-testrunner-components/./dist/components/chat-history.js";
10
11
  import { LlmTestRunner as LlmTestRunnerElement } from "llm-testrunner-components/./dist/components/llm-test-runner.js";
11
12
  export type AppChipsEvents = {
12
13
  onAddChip: EventName<AppChipsCustomEvent<{
@@ -29,6 +30,10 @@ export type AppTextareaEvents = {
29
30
  }>>;
30
31
  };
31
32
  export declare const AppTextarea: StencilReactComponent<AppTextareaElement, AppTextareaEvents>;
33
+ export type ChatHistoryEvents = {
34
+ onChatHistoryChange: EventName<ChatHistoryCustomEvent<ChatHistoryChangeDetail>>;
35
+ };
36
+ export declare const ChatHistory: StencilReactComponent<ChatHistoryElement, ChatHistoryEvents>;
32
37
  export type LlmTestRunnerEvents = {
33
38
  onLlmRequest: EventName<LlmTestRunnerCustomEvent<LLMRequestPayload>>;
34
39
  onSave: EventName<LlmTestRunnerCustomEvent<SavePayload>>;
@@ -1 +1 @@
1
- {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../generated/react/components.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAE7F,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,KAAK,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACtM,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAyC,MAAM,0DAA0D,CAAC;AAC9I,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAA0C,MAAM,2DAA2D,CAAC;AAClJ,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAA4C,MAAM,6DAA6D,CAAC;AAC1J,OAAO,EAAE,aAAa,IAAI,oBAAoB,EAA8C,MAAM,gEAAgE,CAAC;AAGnK,MAAM,MAAM,cAAc,GAAG;IACzB,SAAS,EAAE,SAAS,CAAC,mBAAmB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IAC7D,YAAY,EAAE,SAAS,CAAC,mBAAmB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAClE,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,qBAAqB,CAAC,eAAe,EAAE,cAAc,CAU1E,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG;IAAE,aAAa,EAAE,SAAS,CAAC,oBAAoB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAAE,CAAC;AAEpG,eAAO,MAAM,SAAS,EAAE,qBAAqB,CAAC,gBAAgB,EAAE,eAAe,CAO7E,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG;IAAE,aAAa,EAAE,SAAS,CAAC,sBAAsB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAAE,CAAC;AAExG,eAAO,MAAM,WAAW,EAAE,qBAAqB,CAAC,kBAAkB,EAAE,iBAAiB,CAOnF,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG;IAC9B,YAAY,EAAE,SAAS,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACrE,MAAM,EAAE,SAAS,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC,CAAA;CAC3D,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,qBAAqB,CAAC,oBAAoB,EAAE,mBAAmB,CAUzF,CAAC"}
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../generated/react/components.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAE7F,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,KAAK,sBAAsB,EAAE,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACjQ,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAyC,MAAM,0DAA0D,CAAC;AAC9I,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAA0C,MAAM,2DAA2D,CAAC;AAClJ,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAA4C,MAAM,6DAA6D,CAAC;AAC1J,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAA4C,MAAM,6DAA6D,CAAC;AAC1J,OAAO,EAAE,aAAa,IAAI,oBAAoB,EAA8C,MAAM,gEAAgE,CAAC;AAGnK,MAAM,MAAM,cAAc,GAAG;IACzB,SAAS,EAAE,SAAS,CAAC,mBAAmB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IAC7D,YAAY,EAAE,SAAS,CAAC,mBAAmB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAClE,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,qBAAqB,CAAC,eAAe,EAAE,cAAc,CAU1E,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG;IAAE,aAAa,EAAE,SAAS,CAAC,oBAAoB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAAE,CAAC;AAEpG,eAAO,MAAM,SAAS,EAAE,qBAAqB,CAAC,gBAAgB,EAAE,eAAe,CAO7E,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG;IAAE,aAAa,EAAE,SAAS,CAAC,sBAAsB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAAE,CAAC;AAExG,eAAO,MAAM,WAAW,EAAE,qBAAqB,CAAC,kBAAkB,EAAE,iBAAiB,CAOnF,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG;IAAE,mBAAmB,EAAE,SAAS,CAAC,sBAAsB,CAAC,uBAAuB,CAAC,CAAC,CAAA;CAAE,CAAC;AAEpH,eAAO,MAAM,WAAW,EAAE,qBAAqB,CAAC,kBAAkB,EAAE,iBAAiB,CAOnF,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG;IAC9B,YAAY,EAAE,SAAS,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACrE,MAAM,EAAE,SAAS,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC,CAAA;CAC3D,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,qBAAqB,CAAC,oBAAoB,EAAE,mBAAmB,CAUzF,CAAC"}
@@ -3,6 +3,7 @@ import { createComponent } from '@stencil/react-output-target/runtime';
3
3
  import { AppChips as AppChipsElement, defineCustomElement as defineAppChips } from "llm-testrunner-components/./dist/components/app-chips.js";
4
4
  import { AppSelect as AppSelectElement, defineCustomElement as defineAppSelect } from "llm-testrunner-components/./dist/components/app-select.js";
5
5
  import { AppTextarea as AppTextareaElement, defineCustomElement as defineAppTextarea } from "llm-testrunner-components/./dist/components/app-textarea.js";
6
+ import { ChatHistory as ChatHistoryElement, defineCustomElement as defineChatHistory } from "llm-testrunner-components/./dist/components/chat-history.js";
6
7
  import { LlmTestRunner as LlmTestRunnerElement, defineCustomElement as defineLlmTestRunner } from "llm-testrunner-components/./dist/components/llm-test-runner.js";
7
8
  import React from 'react';
8
9
  export const AppChips = /*@__PURE__*/ createComponent({
@@ -32,6 +33,14 @@ export const AppTextarea = /*@__PURE__*/ createComponent({
32
33
  events: { onValueChange: 'valueChange' },
33
34
  defineCustomElement: defineAppTextarea
34
35
  });
36
+ export const ChatHistory = /*@__PURE__*/ createComponent({
37
+ tagName: 'chat-history',
38
+ elementClass: ChatHistoryElement,
39
+ // @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
40
+ react: React,
41
+ events: { onChatHistoryChange: 'chatHistoryChange' },
42
+ defineCustomElement: defineChatHistory
43
+ });
35
44
  export const LlmTestRunner = /*@__PURE__*/ createComponent({
36
45
  tagName: 'llm-test-runner',
37
46
  elementClass: LlmTestRunnerElement,
@@ -24,6 +24,7 @@ export declare class LLMTestRunner {
24
24
  resetSavingState(): Promise<void>;
25
25
  getTestCases(): Promise<TestCase[]>;
26
26
  private handleTestCaseChange;
27
+ private handleChatHistoryChange;
27
28
  private addNewTestCase;
28
29
  private updateTestCase;
29
30
  private requestLlmText;
@@ -0,0 +1,14 @@
1
+ import { EventEmitter } from '../../../stencil-public-runtime';
2
+ export type ChatHistoryChangeDetail = {
3
+ enabled: boolean;
4
+ value: string;
5
+ };
6
+ export declare class ChatHistory {
7
+ chatHistoryEnabled: boolean;
8
+ chatHistoryValue: string;
9
+ chatHistoryChange: EventEmitter<ChatHistoryChangeDetail>;
10
+ private emit;
11
+ private onToggle;
12
+ private onTextInput;
13
+ render(): any;
14
+ }
@@ -1,6 +1,10 @@
1
1
  import { FunctionalComponent } from '../../../stencil-public-runtime';
2
2
  import { TestCase } from '../../../types/llm-test-runner';
3
3
  import { ExpectedOutcomeChangeDetail } from './expected-outcome-renderer';
4
+ import type { ChatHistoryChangeDetail } from './chat-history';
5
+ export type ChatHistoryRowChangeDetail = {
6
+ testCaseId: string;
7
+ } & ChatHistoryChangeDetail;
4
8
  export interface LLMTestCaseRowProps {
5
9
  testCase: TestCase;
6
10
  dynamicResolutionSupported?: boolean;
@@ -12,5 +16,6 @@ export interface LLMTestCaseRowProps {
12
16
  value: string;
13
17
  }>) => void;
14
18
  onExpectedOutcomeChange: (e: CustomEvent<ExpectedOutcomeChangeDetail>) => void;
19
+ onChatHistoryChange: (e: CustomEvent<ChatHistoryRowChangeDetail>) => void;
15
20
  }
16
21
  export declare const LLMTestCaseRow: FunctionalComponent<LLMTestCaseRowProps>;
@@ -1,5 +1,6 @@
1
1
  import { FunctionalComponent } from '../../../stencil-public-runtime';
2
2
  import { TestCase } from '../../../types/llm-test-runner';
3
+ import { ChatHistoryRowChangeDetail } from './llm-test-case-row';
3
4
  import { ExpectedOutcomeChangeDetail } from './expected-outcome-renderer';
4
5
  export interface LLMTestCasesProps {
5
6
  testCases: TestCase[];
@@ -13,5 +14,6 @@ export interface LLMTestCasesProps {
13
14
  value: string;
14
15
  }>) => void;
15
16
  onExpectedOutcomeChange: (e: CustomEvent<ExpectedOutcomeChangeDetail>) => void;
17
+ onChatHistoryChange: (e: CustomEvent<ChatHistoryRowChangeDetail>) => void;
16
18
  }
17
19
  export declare const LLMTestCases: FunctionalComponent<LLMTestCasesProps>;
@@ -6,10 +6,12 @@
6
6
  */
7
7
  import { HTMLStencilElement, JSXBase } from "./stencil-public-runtime";
8
8
  import { ChipsConfig, SelectConfig, TextAreaConfig } from "./lib/form/schema";
9
+ import { ChatHistoryChangeDetail } from "./components/llm-test-runner/test-cases/chat-history";
9
10
  import { ExpectedOutcomeResolver } from "./lib/test-cases/dynamic-expected-outcome-resolver";
10
11
  import { ExpectedOutcomeSchema, LLMRequestPayload, SavePayload, TestCase } from "./types/llm-test-runner";
11
12
  import { EvaluationResult } from "./lib/evaluation/types";
12
13
  export { ChipsConfig, SelectConfig, TextAreaConfig } from "./lib/form/schema";
14
+ export { ChatHistoryChangeDetail } from "./components/llm-test-runner/test-cases/chat-history";
13
15
  export { ExpectedOutcomeResolver } from "./lib/test-cases/dynamic-expected-outcome-resolver";
14
16
  export { ExpectedOutcomeSchema, LLMRequestPayload, SavePayload, TestCase } from "./types/llm-test-runner";
15
17
  export { EvaluationResult } from "./lib/evaluation/types";
@@ -29,6 +31,16 @@ export namespace Components {
29
31
  "config": TextAreaConfig;
30
32
  "value": string;
31
33
  }
34
+ interface ChatHistory {
35
+ /**
36
+ * @default false
37
+ */
38
+ "chatHistoryEnabled": boolean;
39
+ /**
40
+ * @default ''
41
+ */
42
+ "chatHistoryValue": string;
43
+ }
32
44
  interface LlmTestRunner {
33
45
  "defaultExpectedOutcomeSchema"?: ExpectedOutcomeSchema;
34
46
  /**
@@ -61,6 +73,10 @@ export interface AppTextareaCustomEvent<T> extends CustomEvent<T> {
61
73
  detail: T;
62
74
  target: HTMLAppTextareaElement;
63
75
  }
76
+ export interface ChatHistoryCustomEvent<T> extends CustomEvent<T> {
77
+ detail: T;
78
+ target: HTMLChatHistoryElement;
79
+ }
64
80
  export interface LlmTestRunnerCustomEvent<T> extends CustomEvent<T> {
65
81
  detail: T;
66
82
  target: HTMLLlmTestRunnerElement;
@@ -118,6 +134,23 @@ declare global {
118
134
  prototype: HTMLAppTextareaElement;
119
135
  new (): HTMLAppTextareaElement;
120
136
  };
137
+ interface HTMLChatHistoryElementEventMap {
138
+ "chatHistoryChange": ChatHistoryChangeDetail;
139
+ }
140
+ interface HTMLChatHistoryElement extends Components.ChatHistory, HTMLStencilElement {
141
+ addEventListener<K extends keyof HTMLChatHistoryElementEventMap>(type: K, listener: (this: HTMLChatHistoryElement, ev: ChatHistoryCustomEvent<HTMLChatHistoryElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
142
+ addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
143
+ addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
144
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
145
+ removeEventListener<K extends keyof HTMLChatHistoryElementEventMap>(type: K, listener: (this: HTMLChatHistoryElement, ev: ChatHistoryCustomEvent<HTMLChatHistoryElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
146
+ removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
147
+ removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
148
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
149
+ }
150
+ var HTMLChatHistoryElement: {
151
+ prototype: HTMLChatHistoryElement;
152
+ new (): HTMLChatHistoryElement;
153
+ };
121
154
  interface HTMLLlmTestRunnerElementEventMap {
122
155
  "llmRequest": LLMRequestPayload;
123
156
  "save": SavePayload;
@@ -140,6 +173,7 @@ declare global {
140
173
  "app-chips": HTMLAppChipsElement;
141
174
  "app-select": HTMLAppSelectElement;
142
175
  "app-textarea": HTMLAppTextareaElement;
176
+ "chat-history": HTMLChatHistoryElement;
143
177
  "llm-test-runner": HTMLLlmTestRunnerElement;
144
178
  }
145
179
  }
@@ -163,6 +197,17 @@ declare namespace LocalJSX {
163
197
  "onValueChange"?: (event: AppTextareaCustomEvent<{ value: string }>) => void;
164
198
  "value"?: string;
165
199
  }
200
+ interface ChatHistory {
201
+ /**
202
+ * @default false
203
+ */
204
+ "chatHistoryEnabled"?: boolean;
205
+ /**
206
+ * @default ''
207
+ */
208
+ "chatHistoryValue"?: string;
209
+ "onChatHistoryChange"?: (event: ChatHistoryCustomEvent<ChatHistoryChangeDetail>) => void;
210
+ }
166
211
  interface LlmTestRunner {
167
212
  "defaultExpectedOutcomeSchema"?: ExpectedOutcomeSchema;
168
213
  /**
@@ -189,6 +234,10 @@ declare namespace LocalJSX {
189
234
  interface AppTextareaAttributes {
190
235
  "value": string;
191
236
  }
237
+ interface ChatHistoryAttributes {
238
+ "chatHistoryEnabled": boolean;
239
+ "chatHistoryValue": string;
240
+ }
192
241
  interface LlmTestRunnerAttributes {
193
242
  "delayMs": number;
194
243
  "useSave": boolean;
@@ -199,6 +248,7 @@ declare namespace LocalJSX {
199
248
  "app-chips": AppChips;
200
249
  "app-select": Omit<AppSelect, keyof AppSelectAttributes> & { [K in keyof AppSelect & keyof AppSelectAttributes]?: AppSelect[K] } & { [K in keyof AppSelect & keyof AppSelectAttributes as `attr:${K}`]?: AppSelectAttributes[K] } & { [K in keyof AppSelect & keyof AppSelectAttributes as `prop:${K}`]?: AppSelect[K] };
201
250
  "app-textarea": Omit<AppTextarea, keyof AppTextareaAttributes> & { [K in keyof AppTextarea & keyof AppTextareaAttributes]?: AppTextarea[K] } & { [K in keyof AppTextarea & keyof AppTextareaAttributes as `attr:${K}`]?: AppTextareaAttributes[K] } & { [K in keyof AppTextarea & keyof AppTextareaAttributes as `prop:${K}`]?: AppTextarea[K] };
251
+ "chat-history": Omit<ChatHistory, keyof ChatHistoryAttributes> & { [K in keyof ChatHistory & keyof ChatHistoryAttributes]?: ChatHistory[K] } & { [K in keyof ChatHistory & keyof ChatHistoryAttributes as `attr:${K}`]?: ChatHistoryAttributes[K] } & { [K in keyof ChatHistory & keyof ChatHistoryAttributes as `prop:${K}`]?: ChatHistory[K] };
202
252
  "llm-test-runner": Omit<LlmTestRunner, keyof LlmTestRunnerAttributes> & { [K in keyof LlmTestRunner & keyof LlmTestRunnerAttributes]?: LlmTestRunner[K] } & { [K in keyof LlmTestRunner & keyof LlmTestRunnerAttributes as `attr:${K}`]?: LlmTestRunnerAttributes[K] } & { [K in keyof LlmTestRunner & keyof LlmTestRunnerAttributes as `prop:${K}`]?: LlmTestRunner[K] };
203
253
  }
204
254
  }
@@ -209,6 +259,7 @@ declare module "@stencil/core" {
209
259
  "app-chips": LocalJSX.IntrinsicElements["app-chips"] & JSXBase.HTMLAttributes<HTMLAppChipsElement>;
210
260
  "app-select": LocalJSX.IntrinsicElements["app-select"] & JSXBase.HTMLAttributes<HTMLAppSelectElement>;
211
261
  "app-textarea": LocalJSX.IntrinsicElements["app-textarea"] & JSXBase.HTMLAttributes<HTMLAppTextareaElement>;
262
+ "chat-history": LocalJSX.IntrinsicElements["chat-history"] & JSXBase.HTMLAttributes<HTMLChatHistoryElement>;
212
263
  "llm-test-runner": LocalJSX.IntrinsicElements["llm-test-runner"] & JSXBase.HTMLAttributes<HTMLLlmTestRunnerElement>;
213
264
  }
214
265
  }
@@ -1,3 +1,3 @@
1
1
  export { LLMTestRunner } from './components/llm-test-runner/llm-test-runner';
2
- export type { TestCase, LLMRequestPayload } from './types/llm-test-runner';
2
+ export type { TestCase, TestCaseChatHistory, LLMRequestPayload, } from './types/llm-test-runner';
3
3
  export type * from './components.d.ts';
@@ -3,6 +3,10 @@ export interface TestSuiteExportData {
3
3
  id: string;
4
4
  question: string;
5
5
  expectedOutcome: ExpectedOutcomeField[];
6
+ chatHistory: {
7
+ enabled: boolean;
8
+ value: string;
9
+ };
6
10
  }
7
11
  /**
8
12
  * Formats test cases as a JSON string suitable for saving as a test suite
@@ -1,5 +1,9 @@
1
1
  import { z } from 'zod';
2
2
  import type { EvaluationResult } from '../lib/evaluation/types';
3
+ export declare const testCaseChatHistorySchema: z.ZodObject<{
4
+ enabled: z.ZodBoolean;
5
+ value: z.ZodString;
6
+ }, z.core.$strip>;
3
7
  export declare const testCaseInputSchema: z.ZodObject<{
4
8
  id: z.ZodString;
5
9
  question: z.ZodString;
@@ -47,6 +51,10 @@ export declare const testCaseInputSchema: z.ZodObject<{
47
51
  }, z.core.$strip>>;
48
52
  value: z.ZodString;
49
53
  }, z.core.$strip>], "type">>;
54
+ chatHistory: z.ZodOptional<z.ZodObject<{
55
+ enabled: z.ZodBoolean;
56
+ value: z.ZodString;
57
+ }, z.core.$strip>>;
50
58
  }, z.core.$strip>;
51
59
  export declare const testCaseInputArraySchema: z.ZodArray<z.ZodObject<{
52
60
  id: z.ZodString;
@@ -95,6 +103,10 @@ export declare const testCaseInputArraySchema: z.ZodArray<z.ZodObject<{
95
103
  }, z.core.$strip>>;
96
104
  value: z.ZodString;
97
105
  }, z.core.$strip>], "type">>;
106
+ chatHistory: z.ZodOptional<z.ZodObject<{
107
+ enabled: z.ZodBoolean;
108
+ value: z.ZodString;
109
+ }, z.core.$strip>>;
98
110
  }, z.core.$strip>>;
99
111
  export declare const testCaseSchema: z.ZodObject<{
100
112
  id: z.ZodString;
@@ -143,12 +155,17 @@ export declare const testCaseSchema: z.ZodObject<{
143
155
  }, z.core.$strip>>;
144
156
  value: z.ZodString;
145
157
  }, z.core.$strip>], "type">>;
158
+ chatHistory: z.ZodObject<{
159
+ enabled: z.ZodBoolean;
160
+ value: z.ZodString;
161
+ }, z.core.$strip>;
146
162
  output: z.ZodOptional<z.ZodString>;
147
163
  isRunning: z.ZodOptional<z.ZodBoolean>;
148
164
  error: z.ZodOptional<z.ZodString>;
149
165
  evaluationResult: z.ZodOptional<z.ZodCustom<EvaluationResult, EvaluationResult>>;
150
166
  responseTime: z.ZodOptional<z.ZodNumber>;
151
167
  }, z.core.$strip>;
168
+ export type TestCaseChatHistory = z.infer<typeof testCaseChatHistorySchema>;
152
169
  export type TestCaseInput = z.input<typeof testCaseInputSchema>;
153
170
  export type TestCase = z.input<typeof testCaseSchema>;
154
171
  export declare function validateTestCaseInput(data: unknown): asserts data is TestCaseInput;
@@ -1,8 +1,9 @@
1
1
  import type { TestCase } from './test-case';
2
2
  export type { ExpectedOutcomeMode, ExpectedOutcomeFieldType, ExpectedOutcomeBase, ExpectedOutcomeSchema, ExpectedOutcomeSchemaField, ExpectedOutcomeField, TextExpectedOutcomeSchemaField, TextareaExpectedOutcomeSchemaField, ChipsExpectedOutcomeSchemaField, SelectExpectedOutcomeSchemaField, TextExpectedOutcomeField, TextareaExpectedOutcomeField, ChipsExpectedOutcomeField, SelectExpectedOutcomeField, } from './expected-outcome';
3
- export type { TestCase, TestCaseInput, } from './test-case';
3
+ export type { TestCaseChatHistory, TestCase, TestCaseInput, } from './test-case';
4
4
  export interface LLMRequestPayload {
5
5
  prompt: string;
6
+ chatHistory?: string;
6
7
  resolve: (result: string) => void;
7
8
  reject: (err: Error | unknown) => void;
8
9
  }
@@ -1 +1 @@
1
- export type { TestCaseInput, TestCase, } from '../schemas/test-case';
1
+ export type { TestCaseChatHistory, TestCaseInput, TestCase, } from '../schemas/test-case';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-testrunner-components",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "A Stencil web component library for LLM test runner functionality",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.js",
@@ -1 +0,0 @@
1
- {"file":"app-chips_4.cjs.entry.js","mappings":"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","names":["h"],"sources":["src/lib/form/components/app-chips.css?tag=app-chips&encapsulation=shadow","src/lib/form/components/app-chips.tsx","src/lib/form/components/app-select.css?tag=app-select&encapsulation=shadow","src/lib/form/components/app-select.tsx","src/lib/form/components/app-textarea.css?tag=app-textarea&encapsulation=shadow","src/lib/form/components/app-textarea.tsx"],"sourcesContent":[".app-chips {\n margin-bottom: var(--spacing-4);\n}\n\n.app-chips__label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.app-chips__container {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-2);\n align-items: center;\n}\n\n.app-chips__chip {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2);\n padding: var(--spacing-1) var(--spacing-2);\n font-size: var(--font-size-xs);\n font-weight: var(--font-weight-medium);\n border-radius: var(--radius-md);\n background: var(--accent);\n border: var(--border-width) solid var(--border);\n}\n\n/* Keyword-style chip override (non-URL chips) */\n.app-chips__chip:not(:has(a)) {\n background: var(--info);\n color: var(--info-foreground);\n border: none;\n border-radius: var(--radius-2xl);\n}\n\n.app-chips__link {\n color: var(--info);\n text-decoration: none;\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.app-chips__link:hover {\n text-decoration: underline;\n}\n\n.app-chips__remove {\n background: none;\n border: none;\n cursor: pointer;\n font-size: var(--font-size-xs);\n padding: 0;\n width: var(--spacing-4);\n height: var(--spacing-4);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--radius-full);\n color: var(--muted-foreground);\n opacity: var(--opacity-muted);\n}\n\n.app-chips__chip:not(:has(a)) .app-chips__remove {\n color: var(--info-foreground);\n opacity: var(--opacity-hover);\n}\n\n.app-chips__remove:hover {\n opacity: 1;\n background: var(--muted);\n}\n\n.app-chips__chip:not(:has(a)) .app-chips__remove:hover {\n background: rgba(255, 255, 255, 0.2);\n}\n\n.app-chips__input {\n border: var(--border-width) solid var(--input);\n border-radius: var(--radius-md);\n padding: var(--spacing-2);\n font-size: var(--font-size-xs);\n outline: none;\n min-width: 120px;\n background: var(--background);\n color: var(--foreground);\n}\n\n.app-chips__input:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n","import { Component, Prop, h, Event, EventEmitter } from '@stencil/core';\nimport { ChipsConfig } from '../schema';\n\n@Component({\n tag: 'app-chips',\n styleUrl: 'app-chips.css',\n shadow: true,\n})\nexport class AppChips {\n @Prop() value: string[] = [];\n @Prop() config: ChipsConfig;\n\n @Event() addChip: EventEmitter<{ value: string }>;\n\n @Event() removeChip: EventEmitter<{ value: string }>;\n\n private emitAddChip(val: string) {\n this.addChip.emit({\n value: val,\n });\n }\n\n private emitRemoveChip(value: string) {\n this.removeChip.emit({\n value,\n });\n }\n\n private hasDuplicateChip(value: string): boolean {\n const normalized = value.trim().toLowerCase();\n return this.value.some(chip => chip.trim().toLowerCase() === normalized);\n }\n\n render() {\n const c = this.config;\n\n const allowedAttrs = {\n placeholder: c.placeholder,\n required: c.required,\n disabled: c.disabled,\n readOnly: c.readOnly,\n id: c.name,\n name: c.name,\n autocomplete: c.autocomplete,\n };\n\n return (\n <div class=\"app-chips\">\n {c.label && (\n <label class=\"app-chips__label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <div class=\"app-chips__container\">\n {this.value.map((chip) => (\n <span class=\"app-chips__chip\" key={chip}>\n {c.type === 'url' ? (\n <a\n href={chip}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"app-chips__link\"\n >\n {chip}\n </a>\n ) : (\n chip\n )}\n\n <button\n class=\"app-chips__remove\"\n type=\"button\"\n onClick={() => this.emitRemoveChip(chip)}\n >\n ×\n </button>\n </span>\n ))}\n\n <input\n class=\"app-chips__input\"\n type={c.type || 'text'}\n {...allowedAttrs}\n onKeyDown={(e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n const input = e.target as HTMLInputElement;\n const val = input.value.trim();\n if (!val) return;\n if (this.hasDuplicateChip(val)) {\n input.value = '';\n return;\n }\n\n this.emitAddChip(val);\n input.value = '';\n }\n }}\n />\n </div>\n </div>\n );\n }\n}\n",".app-select {\n margin-bottom: var(--spacing-4);\n}\n\n.app-select__label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.app-select__select {\n border: var(--border-width) solid var(--input);\n border-radius: var(--radius-md);\n font-size: var(--font-size-sm);\n font-weight: var(--font-weight-medium);\n padding: var(--spacing-1) var(--spacing-2);\n outline: none;\n background: var(--background);\n width: 145px;\n color: var(--foreground);\n}\n\n.app-select__select:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\nimport { SelectConfig } from '../schema';\n\n@Component({\n tag: 'app-select',\n styleUrl: 'app-select.css',\n shadow: true,\n})\nexport class AppSelect {\n @Prop() value: string;\n @Prop() config: SelectConfig;\n @Event() valueChange: EventEmitter<{ value: string }>;\n\n render() {\n const c = this.config;\n const allowedAttrs = {\n id: c.name,\n name: c.name,\n disabled: c.disabled,\n required: c.required,\n readOnly: c.readOnly,\n placeholder: c.placeholder,\n autocomplete: c.autocomplete,\n };\n return (\n <div class=\"app-select\">\n {c.label && (\n <label class=\"app-select__label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <div>\n <select\n {...allowedAttrs}\n class=\"app-select__select\"\n onInput={(e: Event) => {\n const raw = (e.target as HTMLSelectElement).value;\n const matched = c.optionList.find(opt => String(opt) === raw);\n this.valueChange.emit({\n value: matched !== undefined ? matched : raw,\n });\n }}\n >\n {c.optionList?.map(option => (\n <option\n value={String(option)}\n key={String(option)}\n selected={this.value === option}\n >\n {String(option)}\n </option>\n ))}\n </select>\n </div>\n </div>\n );\n }\n}\n",".textarea-wrapper {\n margin-bottom: var(--spacing-4);\n}\n\n.textarea-label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.textarea-element {\n width: 95%;\n box-sizing: border-box;\n padding: var(--spacing-3);\n border: 2px solid var(--input);\n border-radius: var(--radius);\n font-size: var(--font-size-sm);\n resize: vertical;\n outline: none;\n transition: border-color 0.2s ease;\n font-family: inherit;\n background: var(--background);\n color: var(--foreground);\n}\n\n.textarea-element:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.textarea-wrapper--read-only .textarea-label {\n color: var(--muted-foreground);\n}\n\n.textarea-element:read-only {\n background: var(--muted);\n color: var(--muted-foreground);\n border-color: var(--border);\n cursor: not-allowed;\n resize: none;\n}\n\n.textarea-element:read-only:focus {\n border-color: var(--border);\n box-shadow: none;\n}\n\n.help-text {\n margin-top: var(--spacing-1);\n font-size: var(--font-size-xs);\n color: var(--muted-foreground, #6b7280);\n line-height: 1.4;\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\nimport { TextAreaConfig } from '../schema';\n\n@Component({\n tag: 'app-textarea',\n styleUrl: 'app-textarea.css',\n shadow: true,\n})\nexport class AppTextarea {\n @Prop() value: string;\n @Prop() config: TextAreaConfig;\n\n @Event() valueChange: EventEmitter<{ value: string }>;\n\n private handleChange = (e: Event) => {\n const target = e.target as HTMLTextAreaElement;\n\n this.valueChange.emit({\n value: target.value,\n });\n };\n\n render() {\n const c = this.config;\n\n const allowedAttrs = {\n placeholder: c.placeholder,\n required: c.required,\n disabled: c.disabled,\n readOnly: c.readOnly,\n rows: c.rows,\n id: c.name,\n name: c.name,\n autocomplete: c.autocomplete,\n };\n\n return (\n <div\n class={{\n 'textarea-wrapper': true,\n 'textarea-wrapper--read-only': !!c.readOnly,\n }}\n >\n {c.label && (\n <label class=\"textarea-label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <textarea\n {...allowedAttrs}\n class=\"textarea-element\"\n value={this.value}\n onInput={this.handleChange}\n ></textarea>\n\n {c.helpText && <p class=\"help-text\">{c.helpText}</p>}\n </div>\n );\n }\n}\n"],"version":3}