uni-textarea-field 1.0.0 → 1.0.2

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/index.html CHANGED
@@ -40,10 +40,8 @@ body{position:relative;inline-size:100vw;block-size:100vh;margin:0;}
40
40
  }
41
41
 
42
42
  uni-textarea-field {
43
- inline-size: 300px;
44
-
45
43
  &::part(icon-subject) {
46
- /*background-color: red;*/
44
+ /* style icon here */
47
45
  }
48
46
 
49
47
  &[data-hide-icon]::part(icon-subject) {
@@ -415,29 +413,21 @@ const handler = (evt) => {
415
413
  } else {
416
414
  textarea.removeAttribute('maxlength');
417
415
  }
418
-
419
- uniTextareaField.refresh();
420
416
  break;
421
417
  }
422
418
 
423
419
  case 'required': {
424
420
  textarea.required = fd['required'] === 'y';
425
-
426
- uniTextareaField.refresh();
427
421
  break;
428
422
  }
429
423
 
430
424
  case 'disabled': {
431
425
  textarea.disabled = fd['disabled'] === 'y';
432
-
433
- uniTextareaField.refresh();
434
426
  break;
435
427
  }
436
428
 
437
429
  case 'readonly': {
438
430
  textarea.readOnly = fd['readonly'] === 'y';
439
-
440
- uniTextareaField.refresh();
441
431
  break;
442
432
  }
443
433
 
@@ -82,34 +82,15 @@ ${_uniColorPalette}
82
82
  }
83
83
 
84
84
  :host {
85
- &:has([slot="textarea"][required]) {
86
- .main__subject__span::after {
87
- content: '*';
88
- color: var(--ct_icon_moderate_strong);
89
- margin-inline-start: 4px;
90
- }
91
- }
92
-
93
- &:has([slot="textarea"][maxlength]) {
94
- .main {
95
- --counter-display: block;
96
- }
97
- }
98
-
99
- &:has([slot="textarea"][readonly]) {
85
+ @container style(--show-required-sign: 'true') {
100
86
  .main {
101
- --background-color: transparent;
102
- --border-color: var(--border-color-readonly);
87
+ --required-sign-display: inline;
103
88
  }
104
89
  }
105
90
 
106
- &:has([slot="textarea"][disabled],[slot="textarea"][inert]) {
91
+ @container style(--show-counter: 'true') {
107
92
  .main {
108
- --text-color: var(--text-color-disabled);
109
- }
110
-
111
- slot[name="textarea"] {
112
- interactivity: inert;
93
+ --counter-display: block;
113
94
  }
114
95
  }
115
96
 
@@ -158,6 +139,7 @@ ${_uniColorPalette}
158
139
  --counter-color: var(--uni-textarea-field-counter-color, var(--ct_text_main_subtle));
159
140
  --caret-color: var(--uni-textarea-field-caret-color, var(--ct_input-caret_main_general));
160
141
 
142
+ --required-sign-display: none;
161
143
  --min-block-size: var(--uni-textarea-field-min-block-size, 100px);
162
144
 
163
145
  /* size */
@@ -189,6 +171,13 @@ ${_uniColorPalette}
189
171
  font-size: 12px;
190
172
  color: var(--subject-color);
191
173
  line-height: 1.667;
174
+
175
+ &::after {
176
+ content: '*';
177
+ color: var(--ct_icon_moderate_strong);
178
+ margin-inline-start: 4px;
179
+ display: var(--required-sign-display);
180
+ }
192
181
  }
193
182
 
194
183
  em {
@@ -269,6 +258,15 @@ ${_uniColorPalette}
269
258
  color: var(--placeholder-color);
270
259
  }
271
260
  }
261
+
262
+ ::slotted(textarea[readonly]) {
263
+ --background-color: transparent;
264
+ --border-color: var(--border-color-readonly);
265
+ }
266
+
267
+ ::slotted(textarea:is([disabled],[inert])) {
268
+ --text-color: var(--text-color-disabled);
269
+ }
272
270
  }
273
271
  </style>
274
272
 
@@ -285,6 +283,40 @@ ${_uniColorPalette}
285
283
  </div>
286
284
  `;
287
285
 
286
+ /* style injection */
287
+ const styleInjection = `
288
+ uni-textarea-field {
289
+ --show-required-sign: 'false';
290
+ --show-counter: 'false';
291
+
292
+ &:has(textarea[required]) {
293
+ --show-required-sign: 'true';
294
+ }
295
+
296
+ &:not([data-hide-counter]):has(textarea[maxlength]) {
297
+ --show-counter: 'true';
298
+ }
299
+ }
300
+
301
+ [inert] uni-textarea-field {
302
+ --interactivity: inert;
303
+ }
304
+ `;
305
+
306
+ const INJECT_KEY = Symbol.for('uni.textarea.field.ui.injected');
307
+ const uiInit = () => {
308
+ if (window[INJECT_KEY]) {
309
+ return;
310
+ }
311
+
312
+ const sheet = new CSSStyleSheet();
313
+ sheet.replaceSync(styleInjection);
314
+ document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
315
+
316
+ window[INJECT_KEY] = true;
317
+ };
318
+ uiInit();
319
+
288
320
  export class UniTextareaField extends HTMLElement {
289
321
  #data;
290
322
  #nodes;
@@ -299,7 +331,8 @@ export class UniTextareaField extends HTMLElement {
299
331
 
300
332
  // data
301
333
  this.#data = {
302
- controller: ''
334
+ controller: '',
335
+ elementController: ''
303
336
  };
304
337
 
305
338
  // nodes
@@ -309,6 +342,7 @@ export class UniTextareaField extends HTMLElement {
309
342
  subject: this.shadowRoot.querySelector('.main__subject__span'),
310
343
  message: this.shadowRoot.querySelector('.main__info__message'),
311
344
  counter: this.shadowRoot.querySelector('.main__info__counter'),
345
+ slot: this.shadowRoot.querySelector('slot[name=textarea]'),
312
346
  };
313
347
 
314
348
  // config
@@ -320,11 +354,12 @@ export class UniTextareaField extends HTMLElement {
320
354
  // evts
321
355
  this._onInput = this._onInput.bind(this);
322
356
  this._onKeydown = this._onKeydown.bind(this);
357
+ this._onSlotchange = this._onSlotchange.bind(this);
323
358
  }
324
359
 
325
360
  async connectedCallback() {
326
361
  const { config, error } = await _wcl.getWCConfig(this);
327
- const { textarea } = this.#nodes;
362
+ const { slot } = this.#nodes;
328
363
 
329
364
  if (error) {
330
365
  console.warn(`${_wcl.classToTagName(this.constructor.name)}: ${error}`);
@@ -343,17 +378,14 @@ export class UniTextareaField extends HTMLElement {
343
378
  // evts
344
379
  this.#data.controller = new AbortController();
345
380
  const signal = this.#data.controller.signal;
346
- textarea.addEventListener('input', this._onInput, { signal });
347
- textarea.addEventListener('keydown', this._onKeydown, { signal });
348
-
349
- // init
350
- this._onInput();
381
+ slot.addEventListener('slotchange', this._onSlotchange, { signal });
382
+
383
+ this.#setupEventListeners();
351
384
  }
352
385
 
353
386
  disconnectedCallback() {
354
- if (this.#data?.controller) {
355
- this.#data.controller.abort();
356
- }
387
+ this.#data.controller.abort?.();
388
+ this.#data.elementController.abort?.();
357
389
  }
358
390
 
359
391
  #format(attrName, oldValue, newValue) {
@@ -444,6 +476,22 @@ export class UniTextareaField extends HTMLElement {
444
476
  }
445
477
  }
446
478
 
479
+ #setupEventListeners() {
480
+ this.#data.elementController.abort?.();
481
+
482
+ this.#nodes.textarea = this.querySelector('[slot=textarea]');
483
+
484
+ if (this.#nodes.textarea) {
485
+ this.#data.elementController = new AbortController();
486
+ const signal = this.#data.elementController.signal;
487
+
488
+ this.#nodes.textarea.addEventListener('input', this._onInput, { signal });
489
+ this.#nodes.textarea.addEventListener('keydown', this._onKeydown, { signal });
490
+
491
+ this._onInput();
492
+ }
493
+ }
494
+
447
495
  set subject(value) {
448
496
  if (value) {
449
497
  this.setAttribute('subject', value);
@@ -523,6 +571,10 @@ export class UniTextareaField extends HTMLElement {
523
571
  }
524
572
  }
525
573
 
574
+ _onSlotchange() {
575
+ this.#setupEventListeners();
576
+ }
577
+
526
578
  refresh() {
527
579
  this.hidden = true;
528
580
  this.offsetHeight;
@@ -1,4 +1,4 @@
1
- import{_wcl}from"./common-lib.js";import{_wccss}from"./common-css.js";import{colorPalette as _uniColorPalette}from"https://unpkg.com/uni-input-field/mjs/uni-css.js";const defaults={subject:"",message:"",stat:"",appearance:"filled",size:"medium"},booleanAttrs=[],objectAttrs=[],custumEvents={},template=document.createElement("template");template.innerHTML=`
1
+ import{_wcl}from"./common-lib.js";import{_wccss}from"./common-css.js";import{colorPalette as _uniColorPalette}from"https://unpkg.com/uni-input-field/mjs/uni-css.js";const defaults={subject:"",message:"",stat:"",appearance:"filled",size:"medium"},booleanAttrs=[],objectAttrs=[],custumEvents={},template=document.createElement("template"),styleInjection=(template.innerHTML=`
2
2
  <style>
3
3
  ${_wccss}
4
4
  ${_uniColorPalette}
@@ -63,34 +63,15 @@ ${_uniColorPalette}
63
63
  }
64
64
 
65
65
  :host {
66
- &:has([slot="textarea"][required]) {
67
- .main__subject__span::after {
68
- content: '*';
69
- color: var(--ct_icon_moderate_strong);
70
- margin-inline-start: 4px;
71
- }
72
- }
73
-
74
- &:has([slot="textarea"][maxlength]) {
75
- .main {
76
- --counter-display: block;
77
- }
78
- }
79
-
80
- &:has([slot="textarea"][readonly]) {
66
+ @container style(--show-required-sign: 'true') {
81
67
  .main {
82
- --background-color: transparent;
83
- --border-color: var(--border-color-readonly);
68
+ --required-sign-display: inline;
84
69
  }
85
70
  }
86
71
 
87
- &:has([slot="textarea"][disabled],[slot="textarea"][inert]) {
72
+ @container style(--show-counter: 'true') {
88
73
  .main {
89
- --text-color: var(--text-color-disabled);
90
- }
91
-
92
- slot[name="textarea"] {
93
- interactivity: inert;
74
+ --counter-display: block;
94
75
  }
95
76
  }
96
77
 
@@ -139,6 +120,7 @@ ${_uniColorPalette}
139
120
  --counter-color: var(--uni-textarea-field-counter-color, var(--ct_text_main_subtle));
140
121
  --caret-color: var(--uni-textarea-field-caret-color, var(--ct_input-caret_main_general));
141
122
 
123
+ --required-sign-display: none;
142
124
  --min-block-size: var(--uni-textarea-field-min-block-size, 100px);
143
125
 
144
126
  /* size */
@@ -170,6 +152,13 @@ ${_uniColorPalette}
170
152
  font-size: 12px;
171
153
  color: var(--subject-color);
172
154
  line-height: 1.667;
155
+
156
+ &::after {
157
+ content: '*';
158
+ color: var(--ct_icon_moderate_strong);
159
+ margin-inline-start: 4px;
160
+ display: var(--required-sign-display);
161
+ }
173
162
  }
174
163
 
175
164
  em {
@@ -250,6 +239,15 @@ ${_uniColorPalette}
250
239
  color: var(--placeholder-color);
251
240
  }
252
241
  }
242
+
243
+ ::slotted(textarea[readonly]) {
244
+ --background-color: transparent;
245
+ --border-color: var(--border-color-readonly);
246
+ }
247
+
248
+ ::slotted(textarea:is([disabled],[inert])) {
249
+ --text-color: var(--text-color-disabled);
250
+ }
253
251
  }
254
252
  </style>
255
253
 
@@ -264,4 +262,21 @@ ${_uniColorPalette}
264
262
  <p class="main__info__counter" data-maxlength="?">0</p>
265
263
  </div>
266
264
  </div>
267
- `;class UniTextareaField extends HTMLElement{#data;#nodes;#config;constructor(e){super(),this.attachShadow({mode:"open",delegatesFocus:!0}),this.shadowRoot.appendChild(template.content.cloneNode(!0)),this.#data={controller:""},this.#nodes={styleSheet:this.shadowRoot.querySelector("style"),textarea:this.querySelector("[slot=textarea]"),subject:this.shadowRoot.querySelector(".main__subject__span"),message:this.shadowRoot.querySelector(".main__info__message"),counter:this.shadowRoot.querySelector(".main__info__counter")},this.#config={...defaults,...e},this._onInput=this._onInput.bind(this),this._onKeydown=this._onKeydown.bind(this)}async connectedCallback(){var{config:e,error:t}=await _wcl.getWCConfig(this),a=this.#nodes["textarea"];t?(console.warn(_wcl.classToTagName(this.constructor.name)+": "+t),this.remove()):(this.#config={...this.#config,...e},Object.keys(defaults).forEach(e=>this.#upgradeProperty(e)),this.#data.controller=new AbortController,t=this.#data.controller.signal,a.addEventListener("input",this._onInput,{signal:t}),a.addEventListener("keydown",this._onKeydown,{signal:t}),this._onInput())}disconnectedCallback(){this.#data?.controller&&this.#data.controller.abort()}#format(e,t,a){if(null!==a)switch(e){case"subject":case"message":this.#config[e]=a;break;case"stat":this.#config[e]=["","valid","invalid"].includes(a)?a:defaults.state;break;case"appearance":this.#config[e]=["filled","outlined"].includes(a)?a:defaults.appearance;break;case"size":this.#config[e]=["large","medium","small"].includes(a)?a:defaults.size}else booleanAttrs.includes(e)?this.#config[e]=!1:this.#config[e]=defaults[e]}attributeChangedCallback(e,t,a){if(UniTextareaField.observedAttributes.includes(e))switch(this.#format(e,t,a),e){case"subject":this.#nodes.subject.textContent=this.subject;break;case"message":this.#nodes.message.textContent=this.message}}static get observedAttributes(){return Object.keys(defaults)}static get supportedEvents(){return Object.keys(custumEvents).map(e=>custumEvents[e])}#upgradeProperty(e){let t;UniTextareaField.observedAttributes.includes(e)&&(Object.prototype.hasOwnProperty.call(this,e)?(t=this[e],delete this[e]):t=booleanAttrs.includes(e)?!(!this.hasAttribute(e)&&!this.#config[e]):objectAttrs.includes(e)?this.hasAttribute(e)?this.getAttribute(e):JSON.stringify(this.#config[e]):this.hasAttribute(e)?this.getAttribute(e):this.#config[e],this[e]=t)}set subject(e){e?this.setAttribute("subject",e):this.removeAttribute("subject")}get subject(){return this.#config.subject}set message(e){e?this.setAttribute("message",e):this.removeAttribute("message")}get message(){return this.#config.message}set stat(e){e?this.setAttribute("stat",e):this.removeAttribute("stat")}get stat(){return this.#config.stat}set appearance(e){e?this.setAttribute("appearance",e):this.removeAttribute("appearance")}get appearance(){return this.#config.appearance}set size(e){e?this.setAttribute("size",e):this.removeAttribute("size")}get size(){return this.#config.size}_onInput(e){var{textarea:t,counter:a}=this.#nodes;a.dataset.maxlength=t.maxLength,a.textContent=t.value.length,e&&"invalid"===this.stat&&(this.stat="")}_onKeydown(e){var{key:e,isComposing:t}=e;"Enter"===e&&t&&event.preventDefault()}refresh(){this.hidden=!0,this.offsetHeight,this.hidden=!1}}const S=_wcl.supports(),T=_wcl.classToTagName("UniTextareaField");S.customElements&&S.shadowDOM&&S.template&&!window.customElements.get(T)&&window.customElements.define(_wcl.classToTagName("UniTextareaField"),UniTextareaField);export{UniTextareaField};
265
+ `,`
266
+ uni-textarea-field {
267
+ --show-required-sign: 'false';
268
+ --show-counter: 'false';
269
+
270
+ &:has(textarea[required]) {
271
+ --show-required-sign: 'true';
272
+ }
273
+
274
+ &:not([data-hide-counter]):has(textarea[maxlength]) {
275
+ --show-counter: 'true';
276
+ }
277
+ }
278
+
279
+ [inert] uni-textarea-field {
280
+ --interactivity: inert;
281
+ }
282
+ `),INJECT_KEY=Symbol.for("uni.textarea.field.ui.injected"),uiInit=()=>{var e;window[INJECT_KEY]||((e=new CSSStyleSheet).replaceSync(styleInjection),document.adoptedStyleSheets=[...document.adoptedStyleSheets,e],window[INJECT_KEY]=!0)};uiInit();class UniTextareaField extends HTMLElement{#data;#nodes;#config;constructor(e){super(),this.attachShadow({mode:"open",delegatesFocus:!0}),this.shadowRoot.appendChild(template.content.cloneNode(!0)),this.#data={controller:"",elementController:""},this.#nodes={styleSheet:this.shadowRoot.querySelector("style"),textarea:this.querySelector("[slot=textarea]"),subject:this.shadowRoot.querySelector(".main__subject__span"),message:this.shadowRoot.querySelector(".main__info__message"),counter:this.shadowRoot.querySelector(".main__info__counter"),slot:this.shadowRoot.querySelector("slot[name=textarea]")},this.#config={...defaults,...e},this._onInput=this._onInput.bind(this),this._onKeydown=this._onKeydown.bind(this),this._onSlotchange=this._onSlotchange.bind(this)}async connectedCallback(){var{config:e,error:t}=await _wcl.getWCConfig(this),a=this.#nodes["slot"];t?(console.warn(_wcl.classToTagName(this.constructor.name)+": "+t),this.remove()):(this.#config={...this.#config,...e},Object.keys(defaults).forEach(e=>this.#upgradeProperty(e)),this.#data.controller=new AbortController,t=this.#data.controller.signal,a.addEventListener("slotchange",this._onSlotchange,{signal:t}),this.#setupEventListeners())}disconnectedCallback(){this.#data.controller.abort?.(),this.#data.elementController.abort?.()}#format(e,t,a){if(null!==a)switch(e){case"subject":case"message":this.#config[e]=a;break;case"stat":this.#config[e]=["","valid","invalid"].includes(a)?a:defaults.state;break;case"appearance":this.#config[e]=["filled","outlined"].includes(a)?a:defaults.appearance;break;case"size":this.#config[e]=["large","medium","small"].includes(a)?a:defaults.size}else booleanAttrs.includes(e)?this.#config[e]=!1:this.#config[e]=defaults[e]}attributeChangedCallback(e,t,a){if(UniTextareaField.observedAttributes.includes(e))switch(this.#format(e,t,a),e){case"subject":this.#nodes.subject.textContent=this.subject;break;case"message":this.#nodes.message.textContent=this.message}}static get observedAttributes(){return Object.keys(defaults)}static get supportedEvents(){return Object.keys(custumEvents).map(e=>custumEvents[e])}#upgradeProperty(e){let t;UniTextareaField.observedAttributes.includes(e)&&(Object.prototype.hasOwnProperty.call(this,e)?(t=this[e],delete this[e]):t=booleanAttrs.includes(e)?!(!this.hasAttribute(e)&&!this.#config[e]):objectAttrs.includes(e)?this.hasAttribute(e)?this.getAttribute(e):JSON.stringify(this.#config[e]):this.hasAttribute(e)?this.getAttribute(e):this.#config[e],this[e]=t)}#setupEventListeners(){var e;this.#data.elementController.abort?.(),this.#nodes.textarea=this.querySelector("[slot=textarea]"),this.#nodes.textarea&&(this.#data.elementController=new AbortController,e=this.#data.elementController.signal,this.#nodes.textarea.addEventListener("input",this._onInput,{signal:e}),this.#nodes.textarea.addEventListener("keydown",this._onKeydown,{signal:e}),this._onInput())}set subject(e){e?this.setAttribute("subject",e):this.removeAttribute("subject")}get subject(){return this.#config.subject}set message(e){e?this.setAttribute("message",e):this.removeAttribute("message")}get message(){return this.#config.message}set stat(e){e?this.setAttribute("stat",e):this.removeAttribute("stat")}get stat(){return this.#config.stat}set appearance(e){e?this.setAttribute("appearance",e):this.removeAttribute("appearance")}get appearance(){return this.#config.appearance}set size(e){e?this.setAttribute("size",e):this.removeAttribute("size")}get size(){return this.#config.size}_onInput(e){var{textarea:t,counter:a}=this.#nodes;a.dataset.maxlength=t.maxLength,a.textContent=t.value.length,e&&"invalid"===this.stat&&(this.stat="")}_onKeydown(e){var{key:e,isComposing:t}=e;"Enter"===e&&t&&event.preventDefault()}_onSlotchange(){this.#setupEventListeners()}refresh(){this.hidden=!0,this.offsetHeight,this.hidden=!1}}const S=_wcl.supports(),T=_wcl.classToTagName("UniTextareaField");S.customElements&&S.shadowDOM&&S.template&&!window.customElements.get(T)&&window.customElements.define(_wcl.classToTagName("UniTextareaField"),UniTextareaField);export{UniTextareaField};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uni-textarea-field",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "<uni-textarea-field /> is an encapsulated Web Component built upon the foundation of the uniopen design language. Implementation is straightforward: simply slot a standard textarea element inside <uni-textarea-field />. The component instantly applies a user interface that aligns seamlessly with the uniopen design language guidelines. Furthermore, its visual styles can be dynamically adapted via native HTML attributes or JavaScript properties. The component also exposes comprehensive character count and textarea length metadata, providing users with a clear and intuitive understanding of predefined character constraints.",
5
5
  "keywords": [
6
6
  "web"