@dropi/ui 0.1.3 → 0.1.5

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  var index = require('./index-CuGLZVqo.js');
4
4
 
5
- const dropiRadioButtonCss = () => `:host{display:inline-block}*,*::before,*::after{box-sizing:border-box}.dropi-radio-button{display:flex;align-items:center;justify-content:flex-start;gap:20px}label{display:flex;align-items:center;gap:8px;cursor:pointer;color:var(--Gray-Gray-700, #32394d);font-size:var(--font-size-s, 12px);font-weight:var(--font-weight-regular, 400);line-height:1.5}input[type='radio']{appearance:none;width:20px;height:20px;border:2px solid var(--Gray-Gray-200, #c3c9d9);border-radius:50%;background-color:transparent;position:relative;cursor:pointer;outline:none;flex-shrink:0;display:flex;justify-content:center;align-items:center}input[type='radio']::before{content:'';position:absolute;top:3px;left:3px;width:10px;height:10px;background-color:var(--Primary-Primary-400, #f7b46f);border-radius:50%;display:none}input[type='radio']:checked{border:2px solid var(--Primary-Primary-500, #f49a3d)}input[type='radio']:checked::before{display:block}`;
5
+ const dropiRadioButtonCss = () => `:host{display:inline-block}*,*::before,*::after{box-sizing:border-box}.dropi-radio-button{display:flex;align-items:center;justify-content:flex-start;gap:20px}label{display:flex;flex-direction:row;align-items:center;gap:8px;cursor:pointer;color:var(--Gray-Gray-700, #32394d);font-size:var(--font-size-s, 12px);font-weight:var(--font-weight-regular, 400);line-height:1.5}input[type='radio']{appearance:none;-webkit-appearance:none;width:20px;height:20px;min-width:20px;border:2px solid var(--Gray-Gray-200, #c3c9d9);border-radius:50%;background-color:transparent;position:relative;cursor:pointer;outline:none;flex-shrink:0;align-self:center;vertical-align:middle;margin:0}input[type='radio']::before{content:'';position:absolute;top:3px;left:3px;width:10px;height:10px;background-color:var(--Primary-Primary-400, #f7b46f);border-radius:50%;display:none}input[type='radio']:checked{border:2px solid var(--Primary-Primary-500, #f49a3d)}input[type='radio']:checked::before{display:block}`;
6
6
 
7
7
  const DropiRadioButton = class {
8
8
  constructor(hostRef) {
@@ -13,6 +13,7 @@
13
13
 
14
14
  label {
15
15
  display: flex;
16
+ flex-direction: row;
16
17
  align-items: center;
17
18
  gap: 8px;
18
19
  cursor: pointer;
@@ -24,8 +25,10 @@ label {
24
25
 
25
26
  input[type='radio'] {
26
27
  appearance: none;
28
+ -webkit-appearance: none;
27
29
  width: 20px;
28
30
  height: 20px;
31
+ min-width: 20px;
29
32
  border: 2px solid var(--Gray-Gray-200, #c3c9d9);
30
33
  border-radius: 50%;
31
34
  background-color: transparent;
@@ -33,9 +36,9 @@ input[type='radio'] {
33
36
  cursor: pointer;
34
37
  outline: none;
35
38
  flex-shrink: 0;
36
- display: flex;
37
- justify-content: center;
38
- align-items: center;
39
+ align-self: center;
40
+ vertical-align: middle;
41
+ margin: 0;
39
42
  }
40
43
 
41
44
  input[type='radio']::before {
@@ -1 +1 @@
1
- import{t as e,p as t,H as r,c as i,h as o}from"./index.js";const n=t(class extends r{constructor(e){super(),!1!==e&&this.__registerHost(),this.__attachShadow(),this.dropiChange=i(this,"dropiChange")}label="";name="radio";inputId="radioButton";checked=!1;resetTrigger=!1;dropiChange;onResetTrigger(e){e&&(this.checked=!1)}handleChange(e){this.checked=e.target.checked,this.dropiChange.emit(e)}render(){return o("div",{key:"3b31699bf088bee52465981074c0aea48b6fe112",class:"dropi-radio-button"},o("label",{key:"072d19bd9c88739b849db0e264c65183eaab2132",htmlFor:this.inputId},o("input",{key:"82d1600002e9dc2795cdc5c731997742adc8e2db",id:this.inputId,type:"radio",name:this.name,checked:this.checked,onChange:e=>this.handleChange(e)}),this.label))}static get formAssociated(){return!0}static get watchers(){return{resetTrigger:[{onResetTrigger:0}]}}static get style(){return":host{display:inline-block}*,*::before,*::after{box-sizing:border-box}.dropi-radio-button{display:flex;align-items:center;justify-content:flex-start;gap:20px}label{display:flex;align-items:center;gap:8px;cursor:pointer;color:var(--Gray-Gray-700, #32394d);font-size:var(--font-size-s, 12px);font-weight:var(--font-weight-regular, 400);line-height:1.5}input[type='radio']{appearance:none;width:20px;height:20px;border:2px solid var(--Gray-Gray-200, #c3c9d9);border-radius:50%;background-color:transparent;position:relative;cursor:pointer;outline:none;flex-shrink:0;display:flex;justify-content:center;align-items:center}input[type='radio']::before{content:'';position:absolute;top:3px;left:3px;width:10px;height:10px;background-color:var(--Primary-Primary-400, #f7b46f);border-radius:50%;display:none}input[type='radio']:checked{border:2px solid var(--Primary-Primary-500, #f49a3d)}input[type='radio']:checked::before{display:block}"}},[577,"dropi-radio-button",{label:[1],name:[1],inputId:[1,"input-id"],checked:[1540],resetTrigger:[4,"reset-trigger"]},void 0,{resetTrigger:[{onResetTrigger:0}]}]);function a(){"undefined"!=typeof customElements&&["dropi-radio-button"].forEach((t=>{"dropi-radio-button"===t&&(customElements.get(e(t))||customElements.define(e(t),n))}))}a();const s=n,d=a;export{s as DropiRadioButton,d as defineCustomElement}
1
+ import{t as e,p as r,H as t,c as i,h as o}from"./index.js";const n=r(class extends t{constructor(e){super(),!1!==e&&this.__registerHost(),this.__attachShadow(),this.dropiChange=i(this,"dropiChange")}label="";name="radio";inputId="radioButton";checked=!1;resetTrigger=!1;dropiChange;onResetTrigger(e){e&&(this.checked=!1)}handleChange(e){this.checked=e.target.checked,this.dropiChange.emit(e)}render(){return o("div",{key:"3b31699bf088bee52465981074c0aea48b6fe112",class:"dropi-radio-button"},o("label",{key:"072d19bd9c88739b849db0e264c65183eaab2132",htmlFor:this.inputId},o("input",{key:"82d1600002e9dc2795cdc5c731997742adc8e2db",id:this.inputId,type:"radio",name:this.name,checked:this.checked,onChange:e=>this.handleChange(e)}),this.label))}static get formAssociated(){return!0}static get watchers(){return{resetTrigger:[{onResetTrigger:0}]}}static get style(){return":host{display:inline-block}*,*::before,*::after{box-sizing:border-box}.dropi-radio-button{display:flex;align-items:center;justify-content:flex-start;gap:20px}label{display:flex;flex-direction:row;align-items:center;gap:8px;cursor:pointer;color:var(--Gray-Gray-700, #32394d);font-size:var(--font-size-s, 12px);font-weight:var(--font-weight-regular, 400);line-height:1.5}input[type='radio']{appearance:none;-webkit-appearance:none;width:20px;height:20px;min-width:20px;border:2px solid var(--Gray-Gray-200, #c3c9d9);border-radius:50%;background-color:transparent;position:relative;cursor:pointer;outline:none;flex-shrink:0;align-self:center;vertical-align:middle;margin:0}input[type='radio']::before{content:'';position:absolute;top:3px;left:3px;width:10px;height:10px;background-color:var(--Primary-Primary-400, #f7b46f);border-radius:50%;display:none}input[type='radio']:checked{border:2px solid var(--Primary-Primary-500, #f49a3d)}input[type='radio']:checked::before{display:block}"}},[577,"dropi-radio-button",{label:[1],name:[1],inputId:[1,"input-id"],checked:[1540],resetTrigger:[4,"reset-trigger"]},void 0,{resetTrigger:[{onResetTrigger:0}]}]);function a(){"undefined"!=typeof customElements&&["dropi-radio-button"].forEach((r=>{"dropi-radio-button"===r&&(customElements.get(e(r))||customElements.define(e(r),n))}))}a();const s=n,d=a;export{s as DropiRadioButton,d as defineCustomElement}
@@ -1 +1 @@
1
- import{p as e,g as o,b as t}from"./p-DFz-gwFP.js";export{s as setNonce}from"./p-DFz-gwFP.js";(()=>{const o=import.meta.url,t={};return""!==o&&(t.resourcesUrl=new URL(".",o).href),e(t)})().then((async e=>(await o(),t([["p-6f0aa619",[[513,"dropi-icon",{name:[1],width:[1],height:[1],color:[1]},null,{color:[{colorChanged:0}]}]]],["p-21abf91a",[[769,"dropi-button",{type:[1],severity:[1],size:[1],state:[1],preIcon:[1,"pre-icon"],postIcon:[1,"post-icon"],text:[1]}]]],["p-a46a05a6",[[577,"dropi-input",{inputId:[1,"input-id"],name:[1],label:[1],placeholder:[1],value:[1025],maxlength:[2],disabled:[516],required:[516],showAsterisk:[4,"show-asterisk"],fixedLabel:[4,"fixed-label"],inputMode:[1,"input-mode"],passwordInput:[4,"password-input"],moneyFormat:[4,"money-format"],thousandSeparator:[4,"thousand-separator"],onlyNumbers:[4,"only-numbers"],allowDecimals:[4,"allow-decimals"],onlyLetters:[4,"only-letters"],icon:[1],iconColor:[1,"icon-color"],invalid:[4],helperText:[1,"helper-text"],showHelperOnlyOnError:[4,"show-helper-only-on-error"],showPassword:[32],touched:[32]},null,{value:[{valueChanged:0}],disabled:[{disabledChanged:0}]}]]],["p-c7b9cbda",[[577,"dropi-select",{label:[1],placeholder:[1],options:[1040],name:[1],disabled:[516],invalid:[4],errorText:[1,"error-text"],helperText:[1,"helper-text"],showObligatory:[4,"show-obligatory"],searchEnabled:[4,"search-enabled"],multiSelect:[4,"multi-select"],dropdownType:[4,"dropdown-type"],showCountryFlags:[4,"show-country-flags"],radioOptions:[4,"radio-options"],placeHolderSearch:[1,"place-holder-search"],preIcon:[1,"pre-icon"],defaultSelectedId:[1032,"default-selected-id"],value:[1040],isOpen:[32],selectedOption:[32],multiSelected:[32],filteredOptions:[32],searchTerm:[32],dropdownStyle:[32],setById:[64],setByLabel:[64],clearSelection:[64],resetMultiSelect:[64]},[[4,"click","handleOutsideClick"]],{options:[{optionsChanged:0}],defaultSelectedId:[{defaultChanged:0}],value:[{valueChanged:0}]}]]],["p-52291024",[[513,"dropi-tag",{type:[1],state:[1],showIcon:[4,"show-icon"],icon:[1],text:[1]},null,{type:[{propsChanged:0}],state:[{propsChanged:0}]}]]],["p-9c7076d3",[[577,"dropi-text-area",{inputId:[1,"input-id"],name:[1],label:[1],placeholder:[1],value:[1025],maxlength:[2],minlength:[2],rows:[2],resize:[1],disabled:[516],required:[516],showAsterisk:[4,"show-asterisk"],helperText:[1,"helper-text"],invalid:[4],touched:[32]},null,{value:[{valueChanged:0}]}]]],["p-f785011f",[[513,"dropi-badge",{state:[1]}]]],["p-dd089a60",[[577,"dropi-checkbox",{checked:[1540],disabled:[516]}]]],["p-54502c46",[[577,"dropi-radio-button",{label:[1],name:[1],inputId:[1,"input-id"],checked:[1540],resetTrigger:[4,"reset-trigger"]},null,{resetTrigger:[{onResetTrigger:0}]}]]],["p-a1944f3d",[[577,"dropi-switch",{isChecked:[1540,"is-checked"],disabled:[516]}]]]],e))));
1
+ import{p as e,g as o,b as t}from"./p-DFz-gwFP.js";export{s as setNonce}from"./p-DFz-gwFP.js";(()=>{const o=import.meta.url,t={};return""!==o&&(t.resourcesUrl=new URL(".",o).href),e(t)})().then((async e=>(await o(),t([["p-6f0aa619",[[513,"dropi-icon",{name:[1],width:[1],height:[1],color:[1]},null,{color:[{colorChanged:0}]}]]],["p-21abf91a",[[769,"dropi-button",{type:[1],severity:[1],size:[1],state:[1],preIcon:[1,"pre-icon"],postIcon:[1,"post-icon"],text:[1]}]]],["p-a46a05a6",[[577,"dropi-input",{inputId:[1,"input-id"],name:[1],label:[1],placeholder:[1],value:[1025],maxlength:[2],disabled:[516],required:[516],showAsterisk:[4,"show-asterisk"],fixedLabel:[4,"fixed-label"],inputMode:[1,"input-mode"],passwordInput:[4,"password-input"],moneyFormat:[4,"money-format"],thousandSeparator:[4,"thousand-separator"],onlyNumbers:[4,"only-numbers"],allowDecimals:[4,"allow-decimals"],onlyLetters:[4,"only-letters"],icon:[1],iconColor:[1,"icon-color"],invalid:[4],helperText:[1,"helper-text"],showHelperOnlyOnError:[4,"show-helper-only-on-error"],showPassword:[32],touched:[32]},null,{value:[{valueChanged:0}],disabled:[{disabledChanged:0}]}]]],["p-c7b9cbda",[[577,"dropi-select",{label:[1],placeholder:[1],options:[1040],name:[1],disabled:[516],invalid:[4],errorText:[1,"error-text"],helperText:[1,"helper-text"],showObligatory:[4,"show-obligatory"],searchEnabled:[4,"search-enabled"],multiSelect:[4,"multi-select"],dropdownType:[4,"dropdown-type"],showCountryFlags:[4,"show-country-flags"],radioOptions:[4,"radio-options"],placeHolderSearch:[1,"place-holder-search"],preIcon:[1,"pre-icon"],defaultSelectedId:[1032,"default-selected-id"],value:[1040],isOpen:[32],selectedOption:[32],multiSelected:[32],filteredOptions:[32],searchTerm:[32],dropdownStyle:[32],setById:[64],setByLabel:[64],clearSelection:[64],resetMultiSelect:[64]},[[4,"click","handleOutsideClick"]],{options:[{optionsChanged:0}],defaultSelectedId:[{defaultChanged:0}],value:[{valueChanged:0}]}]]],["p-52291024",[[513,"dropi-tag",{type:[1],state:[1],showIcon:[4,"show-icon"],icon:[1],text:[1]},null,{type:[{propsChanged:0}],state:[{propsChanged:0}]}]]],["p-9c7076d3",[[577,"dropi-text-area",{inputId:[1,"input-id"],name:[1],label:[1],placeholder:[1],value:[1025],maxlength:[2],minlength:[2],rows:[2],resize:[1],disabled:[516],required:[516],showAsterisk:[4,"show-asterisk"],helperText:[1,"helper-text"],invalid:[4],touched:[32]},null,{value:[{valueChanged:0}]}]]],["p-f785011f",[[513,"dropi-badge",{state:[1]}]]],["p-dd089a60",[[577,"dropi-checkbox",{checked:[1540],disabled:[516]}]]],["p-bda1427f",[[577,"dropi-radio-button",{label:[1],name:[1],inputId:[1,"input-id"],checked:[1540],resetTrigger:[4,"reset-trigger"]},null,{resetTrigger:[{onResetTrigger:0}]}]]],["p-a1944f3d",[[577,"dropi-switch",{isChecked:[1540,"is-checked"],disabled:[516]}]]]],e))));
@@ -0,0 +1 @@
1
+ import{r as e,c as r,h as i}from"./p-DFz-gwFP.js";const t=class{constructor(i){e(this,i),this.dropiChange=r(this,"dropiChange")}label="";name="radio";inputId="radioButton";checked=!1;resetTrigger=!1;dropiChange;onResetTrigger(e){e&&(this.checked=!1)}handleChange(e){this.checked=e.target.checked,this.dropiChange.emit(e)}render(){return i("div",{key:"3b31699bf088bee52465981074c0aea48b6fe112",class:"dropi-radio-button"},i("label",{key:"072d19bd9c88739b849db0e264c65183eaab2132",htmlFor:this.inputId},i("input",{key:"82d1600002e9dc2795cdc5c731997742adc8e2db",id:this.inputId,type:"radio",name:this.name,checked:this.checked,onChange:e=>this.handleChange(e)}),this.label))}static get formAssociated(){return!0}static get watchers(){return{resetTrigger:[{onResetTrigger:0}]}}};t.style=":host{display:inline-block}*,*::before,*::after{box-sizing:border-box}.dropi-radio-button{display:flex;align-items:center;justify-content:flex-start;gap:20px}label{display:flex;flex-direction:row;align-items:center;gap:8px;cursor:pointer;color:var(--Gray-Gray-700, #32394d);font-size:var(--font-size-s, 12px);font-weight:var(--font-weight-regular, 400);line-height:1.5}input[type='radio']{appearance:none;-webkit-appearance:none;width:20px;height:20px;min-width:20px;border:2px solid var(--Gray-Gray-200, #c3c9d9);border-radius:50%;background-color:transparent;position:relative;cursor:pointer;outline:none;flex-shrink:0;align-self:center;vertical-align:middle;margin:0}input[type='radio']::before{content:'';position:absolute;top:3px;left:3px;width:10px;height:10px;background-color:var(--Primary-Primary-400, #f7b46f);border-radius:50%;display:none}input[type='radio']:checked{border:2px solid var(--Primary-Primary-500, #f49a3d)}input[type='radio']:checked::before{display:block}";export{t as dropi_radio_button}
@@ -1,6 +1,6 @@
1
1
  import { r as registerInstance, c as createEvent, h } from './index-DFz-gwFP.js';
2
2
 
3
- const dropiRadioButtonCss = () => `:host{display:inline-block}*,*::before,*::after{box-sizing:border-box}.dropi-radio-button{display:flex;align-items:center;justify-content:flex-start;gap:20px}label{display:flex;align-items:center;gap:8px;cursor:pointer;color:var(--Gray-Gray-700, #32394d);font-size:var(--font-size-s, 12px);font-weight:var(--font-weight-regular, 400);line-height:1.5}input[type='radio']{appearance:none;width:20px;height:20px;border:2px solid var(--Gray-Gray-200, #c3c9d9);border-radius:50%;background-color:transparent;position:relative;cursor:pointer;outline:none;flex-shrink:0;display:flex;justify-content:center;align-items:center}input[type='radio']::before{content:'';position:absolute;top:3px;left:3px;width:10px;height:10px;background-color:var(--Primary-Primary-400, #f7b46f);border-radius:50%;display:none}input[type='radio']:checked{border:2px solid var(--Primary-Primary-500, #f49a3d)}input[type='radio']:checked::before{display:block}`;
3
+ const dropiRadioButtonCss = () => `:host{display:inline-block}*,*::before,*::after{box-sizing:border-box}.dropi-radio-button{display:flex;align-items:center;justify-content:flex-start;gap:20px}label{display:flex;flex-direction:row;align-items:center;gap:8px;cursor:pointer;color:var(--Gray-Gray-700, #32394d);font-size:var(--font-size-s, 12px);font-weight:var(--font-weight-regular, 400);line-height:1.5}input[type='radio']{appearance:none;-webkit-appearance:none;width:20px;height:20px;min-width:20px;border:2px solid var(--Gray-Gray-200, #c3c9d9);border-radius:50%;background-color:transparent;position:relative;cursor:pointer;outline:none;flex-shrink:0;align-self:center;vertical-align:middle;margin:0}input[type='radio']::before{content:'';position:absolute;top:3px;left:3px;width:10px;height:10px;background-color:var(--Primary-Primary-400, #f7b46f);border-radius:50%;display:none}input[type='radio']:checked{border:2px solid var(--Primary-Primary-500, #f49a3d)}input[type='radio']:checked::before{display:block}`;
4
4
 
5
5
  const DropiRadioButton = class {
6
6
  constructor(hostRef) {
@@ -5,3 +5,4 @@
5
5
  */
6
6
  export type * from './components.d.ts';
7
7
  export type { BadgeState } from './components/dropi-badge/dropi-badge';
8
+ export type { SelectOption, SelectOptionGroup } from './components/dropi-select/select.types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dropi/ui",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Dropi Design System — Web Components for Angular, React and Vue",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.js",
@@ -33,7 +33,7 @@
33
33
  "scripts/"
34
34
  ],
35
35
  "scripts": {
36
- "build": "stencil build",
36
+ "build": "stencil build && cd ../dropi-ui-react && npm run build",
37
37
  "start": "stencil build --dev --watch --serve",
38
38
  "test": "stencil-test",
39
39
  "test:watch": "stencil-test --watch",
package/readme.md CHANGED
@@ -1,107 +1,514 @@
1
- [![Built With Stencil](https://img.shields.io/badge/-Built%20With%20Stencil-16161d.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjIuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI%2BCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI%2BCgkuc3Qwe2ZpbGw6I0ZGRkZGRjt9Cjwvc3R5bGU%2BCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik00MjQuNywzNzMuOWMwLDM3LjYtNTUuMSw2OC42LTkyLjcsNjguNkgxODAuNGMtMzcuOSwwLTkyLjctMzAuNy05Mi43LTY4LjZ2LTMuNmgzMzYuOVYzNzMuOXoiLz4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTQyNC43LDI5Mi4xSDE4MC40Yy0zNy42LDAtOTIuNy0zMS05Mi43LTY4LjZ2LTMuNkgzMzJjMzcuNiwwLDkyLjcsMzEsOTIuNyw2OC42VjI5Mi4xeiIvPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNDI0LjcsMTQxLjdIODcuN3YtMy42YzAtMzcuNiw1NC44LTY4LjYsOTIuNy02OC42SDMzMmMzNy45LDAsOTIuNywzMC43LDkyLjcsNjguNlYxNDEuN3oiLz4KPC9zdmc%2BCg%3D%3D&colorA=16161d&style=flat-square)](https://stenciljs.com)
1
+ # @dropi/ui
2
2
 
3
- # Stencil Component Starter
3
+ Librería de Web Components del Design System de Dropi, construida con **Stencil.js v4**.
4
+ Genera componentes reutilizables para Angular, React y Vue desde una única base de código.
4
5
 
5
- > This is a starter project for building a standalone Web Components using Stencil.
6
+ - **Paquete npm:** `@dropi/ui` (v0.1.0)
7
+ - **React wrappers:** `@dropi/ui-react`
6
8
 
7
- Stencil is a compiler for building fast web apps using Web Components.
9
+ ---
8
10
 
9
- Stencil combines the best concepts of the most popular frontend frameworks into a compile-time rather than runtime tool. Stencil takes TypeScript, JSX, a tiny virtual DOM layer, efficient one-way data binding, an asynchronous rendering pipeline (similar to React Fiber), and lazy-loading out of the box, and generates 100% standards-based Web Components that run in any browser supporting the Custom Elements specification.
11
+ ## Instalación
10
12
 
11
- Stencil components are just Web Components, so they work in any major framework or with no framework at all.
13
+ | Framework | Paquete a instalar |
14
+ |---|---|
15
+ | React | `npm install @dropi/ui-react` |
16
+ | Angular / Vue / Vanilla | `npm install @dropi/ui` |
12
17
 
13
- ## Getting Started
18
+ > **¿Por qué dos paquetes?**
19
+ > `@dropi/ui` contiene los Web Components puros (estándares del navegador).
20
+ > `@dropi/ui-react` son wrappers React auto-generados por Stencil que los envuelven con props tipadas, eventos estilo React (`onDropiChange`) y autocompletado en VSCode.
21
+ > `@dropi/ui-react` depende internamente de `@dropi/ui` — no necesitas instalar los dos.
14
22
 
15
- To start building a new web component using Stencil, clone this repo to a new directory:
23
+ ---
16
24
 
17
- ```bash
18
- git clone https://github.com/stenciljs/component-starter.git my-component
19
- cd my-component
20
- git remote rm origin
25
+ ## Setup
26
+
27
+ ### React (`main.tsx`)
28
+
29
+ Con `@dropi/ui-react` **no necesitas** llamar `defineCustomElements()` — cada wrapper registra su Web Component automáticamente al importarlo.
30
+
31
+ ```typescript
32
+ import '@dropi/ui/dist/dropi-ui/dropi-ui.css' // estilos globales y tokens
33
+
34
+ // No se necesita defineCustomElements()
35
+ // Solo importa y usa los componentes directamente
21
36
  ```
22
37
 
23
- and run:
38
+ ### Angular (`main.ts`)
24
39
 
25
- ```bash
26
- npm install
27
- npm start
40
+ ```typescript
41
+ import { defineCustomElements } from '@dropi/ui/loader'
42
+ import '@dropi/ui/dist/dropi-ui/dropi-ui.css'
43
+
44
+ defineCustomElements()
45
+ bootstrapApplication(AppComponent, appConfig)
28
46
  ```
29
47
 
30
- To build the component for production, run:
48
+ En módulos o componentes Angular que usen tags `<dropi-*>`, agregar el schema:
31
49
 
32
- ```bash
33
- npm run build
50
+ ```typescript
51
+ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
52
+
53
+ @NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })
54
+ // o en standalone:
55
+ @Component({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })
34
56
  ```
35
57
 
36
- To run the unit tests for the components, run:
58
+ ### Assets (íconos)
37
59
 
38
- ```bash
39
- npm test
60
+ El componente `<dropi-icon>` requiere el sprite en `/assets/icons/symbol/svg/sprite.css.svg`.
61
+
62
+ **Angular** — en `angular.json`:
63
+ ```json
64
+ "assets": [
65
+ { "glob": "sprite.css.svg", "input": "node_modules/@dropi/ui/dist/dropi-ui/assets/icons/symbol/svg/", "output": "assets/icons/symbol/svg/" }
66
+ ]
40
67
  ```
41
68
 
42
- Need help? Check out our docs [here](https://stenciljs.com/docs/my-first-component).
69
+ **React/Vite** copiar a `public/assets/icons/symbol/svg/`.
43
70
 
44
- ## Naming Components
71
+ ---
45
72
 
46
- When creating new component tags, we recommend _not_ using `stencil` in the component name (ex: `<stencil-datepicker>`). This is because the generated component has little to nothing to do with Stencil; it's just a web component!
73
+ ## Cómo pasar props regla fundamental
47
74
 
48
- Instead, use a prefix that fits your company or any name for a group of related components. For example, all of the [Ionic-generated](https://ionicframework.com/) web components use the prefix `ion`.
75
+ Cada prop se pasa **directamente en el JSX**, una por una. No existe un prop contenedor tipo `selectProperties` u `options` agrupadas.
49
76
 
50
- ## Using this component
77
+ ```tsx
78
+ // ❌ Incorrecto — selectProperties no existe como prop
79
+ <DropiSelect selectProperties={{ label: 'País', placeholder: 'Seleccionar' }} />
80
+
81
+ // ✅ Correcto — cada prop va suelta en el tag
82
+ <DropiSelect
83
+ label="País"
84
+ placeholder="Seleccionar"
85
+ options={options}
86
+ onDropiChange={(e) => setSelected(e.detail)}
87
+ />
88
+ ```
51
89
 
52
- There are two strategies we recommend for using web components built with Stencil.
90
+ Esto aplica para todos los componentes. Las props disponibles están listadas en cada sección de este readme.
53
91
 
54
- The first step for all two of these strategies is to [publish to NPM](https://docs.npmjs.com/getting-started/publishing-npm-packages).
92
+ > **Intellisense en VSCode:** si al hacer hover sobre un componente no aparecen las props, significa que `@dropi/ui-react` necesita ser compilado (`npm run build` en la carpeta `dropi-ui-react`). Después de cualquier cambio en la librería siempre hay que correr el build.
55
93
 
56
- You can read more about these different approaches in the [Stencil docs](https://stenciljs.com/docs/publishing).
94
+ ---
57
95
 
58
- ### Lazy Loading
96
+ ## Nota importante sobre eventos
59
97
 
60
- If your Stencil project is built with the [`dist`](https://stenciljs.com/docs/distribution) output target, you can import a small bootstrap script that registers all components and allows you to load individual component scripts lazily.
98
+ Todos los eventos son `CustomEvent`. El valor emitido **siempre viene en `e.detail`**, no en `e` directamente.
61
99
 
62
- For example, given your Stencil project namespace is called `my-design-system`, to use `my-component` on any website, inject this into your HTML:
100
+ ```typescript
101
+ // ❌ Incorrecto — e es el CustomEvent completo, no el valor
102
+ onDropiChange={(e) => console.log(e)}
63
103
 
104
+ // ✅ Correcto — e.detail tiene el valor real
105
+ onDropiChange={(e) => console.log(e.detail)}
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Componentes
111
+
112
+ ---
113
+
114
+ ### `<dropi-button>`
115
+
116
+ Botón de acción principal con múltiples variantes de tipo, apariencia, tamaño y estado.
117
+
118
+ **Props**
119
+
120
+ | Prop | Tipo | Default | Descripción |
121
+ |---|---|---|---|
122
+ | `type` | `'legacy' \| 'default' \| 'success' \| 'info' \| 'error' \| 'warning' \| 'dropdown'` | `'default'` | Paleta de color |
123
+ | `severity` | `'primary' \| 'secondary' \| 'tertiary'` | `'primary'` | Relleno: filled / outlined / ghost |
124
+ | `size` | `'large' \| 'normal' \| 'small'` | `'normal'` | Tamaño |
125
+ | `state` | `'default' \| 'disabled' \| 'loading'` | `'default'` | Estado |
126
+ | `text` | `string` | `''` | Texto del label |
127
+ | `preIcon` | `string` | `''` | Ícono antes del texto |
128
+ | `postIcon` | `string` | `''` | Ícono después del texto |
129
+
130
+ **Eventos**
131
+
132
+ | Evento | `e.detail` | Cuándo |
133
+ |---|---|---|
134
+ | `dropiClick` | `MouseEvent` | Al hacer click (no se emite si `state` es `disabled` o `loading`) |
135
+
136
+ **Ejemplo React**
137
+ ```tsx
138
+ <DropiButton
139
+ text="Guardar"
140
+ severity="primary"
141
+ size="normal"
142
+ onDropiClick={(e) => console.log(e.detail)}
143
+ />
144
+ ```
145
+
146
+ **Ejemplo Angular**
64
147
  ```html
65
- <script type="module" src="https://unpkg.com/my-design-system"></script>
66
- <!--
67
- To avoid unpkg.com redirects to the actual file, you can also directly import:
68
- https://unpkg.com/foobar-design-system@0.0.1/dist/foobar-design-system/foobar-design-system.esm.js
69
- -->
70
- <my-component first="Stencil" middle="'Don't call me a framework'" last="JS"></my-component>
148
+ <dropi-button text="Guardar" severity="primary" (dropiClick)="onSave($event)"></dropi-button>
71
149
  ```
72
150
 
73
- This will only load the necessary scripts needed to render `<my-component />`. Once more components of this package are used, they will automatically be loaded lazily.
151
+ ---
152
+
153
+ ### `<dropi-checkbox>`
154
+
155
+ Checkbox estilizado con soporte para formularios nativos.
156
+
157
+ **Props**
158
+
159
+ | Prop | Tipo | Default | Descripción |
160
+ |---|---|---|---|
161
+ | `checked` | `boolean` | `false` | Estado del checkbox |
162
+ | `disabled` | `boolean` | `false` | Deshabilita el checkbox |
74
163
 
75
- You can also import the script as part of your `node_modules` in your applications entry file:
164
+ **Eventos**
76
165
 
166
+ | Evento | `e.detail` | Cuándo |
167
+ |---|---|---|
168
+ | `dropiChange` | `boolean` | Al cambiar el estado (`true` = marcado, `false` = desmarcado) |
169
+
170
+ > `e.detail` es el boolean directamente. Si ves "el objeto completo" es porque estás leyendo `e` en vez de `e.detail`.
171
+
172
+ **Ejemplo React**
77
173
  ```tsx
78
- import 'foobar-design-system/dist/foobar-design-system/foobar-design-system.esm.js';
174
+ const [checked, setChecked] = useState(false)
175
+
176
+ <DropiCheckbox
177
+ checked={checked}
178
+ onDropiChange={(e) => setChecked(e.detail)}
179
+ />
180
+ ```
181
+
182
+ **Ejemplo Angular**
183
+ ```html
184
+ <dropi-checkbox [checked]="checked" (dropiChange)="checked = $event.detail"></dropi-checkbox>
79
185
  ```
80
186
 
81
- Check out this [Live Demo](https://stackblitz.com/edit/vitejs-vite-y6v26a?file=src%2Fmain.tsx).
187
+ ---
82
188
 
83
- ### Standalone
189
+ ### `<dropi-switch>`
84
190
 
85
- If you are using a Stencil component library with `dist-custom-elements`, we recommend importing Stencil components individually in those files where they are needed.
191
+ Toggle switch on/off.
86
192
 
87
- To export Stencil components as standalone components make sure you have the [`dist-custom-elements`](https://stenciljs.com/docs/custom-elements) output target defined in your `stencil.config.ts`.
193
+ **Props**
88
194
 
89
- For example, given you'd like to use `<my-component />` as part of a React component, you can import the component directly via:
195
+ | Prop | Tipo | Default | Descripción |
196
+ |---|---|---|---|
197
+ | `isChecked` | `boolean` | `false` | Estado del switch |
198
+ | `disabled` | `boolean` | `false` | Deshabilita el switch |
90
199
 
200
+ **Eventos**
201
+
202
+ | Evento | `e.detail` | Cuándo |
203
+ |---|---|---|
204
+ | `dropiChange` | `boolean` | Al togglear (`true` = encendido, `false` = apagado) |
205
+
206
+ **Ejemplo React**
207
+ ```tsx
208
+ const [on, setOn] = useState(false)
209
+
210
+ <DropiSwitch isChecked={on} onDropiChange={(e) => setOn(e.detail)} />
211
+ ```
212
+
213
+ ---
214
+
215
+ ### `<dropi-input>`
216
+
217
+ Campo de texto con label flotante, validación, ícono, toggle de contraseña, formato monetario y asociación nativa a formularios.
218
+
219
+ **Props**
220
+
221
+ | Prop | Tipo | Default | Descripción |
222
+ |---|---|---|---|
223
+ | `value` | `string` | `''` | Valor controlado |
224
+ | `label` | `string` | `''` | Label flotante o fija |
225
+ | `placeholder` | `string` | `' '` | Placeholder |
226
+ | `name` | `string` | `''` | Nombre para formularios nativos |
227
+ | `inputId` | `string` | `''` | ID del input (default: valor del label) |
228
+ | `disabled` | `boolean` | `false` | Deshabilita el campo |
229
+ | `required` | `boolean` | `false` | Marca como requerido |
230
+ | `showAsterisk` | `boolean` | `true` | Muestra asterisco cuando `required` |
231
+ | `fixedLabel` | `boolean` | `false` | Label fija arriba en vez de flotante |
232
+ | `inputMode` | `'text' \| 'numeric' \| 'decimal' \| 'tel' \| 'email' \| 'url' \| 'search'` | `'text'` | Teclado en móvil |
233
+ | `maxlength` | `number` | — | Longitud máxima |
234
+ | `invalid` | `boolean` | `false` | Marca el campo como inválido |
235
+ | `helperText` | `string` | `''` | Texto de ayuda o error debajo |
236
+ | `showHelperOnlyOnError` | `boolean` | `false` | Solo muestra helperText cuando inválido |
237
+ | `passwordInput` | `boolean` | `false` | Modo contraseña con toggle ojo |
238
+ | `moneyFormat` | `boolean` | `false` | Formato `$1,000,000` |
239
+ | `thousandSeparator` | `boolean` | `false` | Formato `1,000,000` sin símbolo |
240
+ | `onlyNumbers` | `boolean` | `false` | Solo permite números |
241
+ | `allowDecimals` | `boolean` | `false` | Permite decimales (con `onlyNumbers`) |
242
+ | `onlyLetters` | `boolean` | `false` | Solo permite letras |
243
+ | `icon` | `string` | `''` | Nombre del ícono (visible solo si hay valor) |
244
+ | `iconColor` | `string` | `'Gray-Gray-400'` | Token de color del ícono |
245
+
246
+ **Eventos**
247
+
248
+ | Evento | `e.detail` | Cuándo |
249
+ |---|---|---|
250
+ | `dropiInput` | `string` | En cada tecla (keystroke) |
251
+ | `dropiChange` | `string` | Al perder el foco (blur) |
252
+ | `dropiFocus` | `void` | Al enfocar el campo |
253
+ | `dropiBlur` | `void` | Al desenfocar el campo |
254
+
255
+ **Ejemplo React**
91
256
  ```tsx
92
- import 'foobar-design-system/my-component';
93
-
94
- function App() {
95
- return (
96
- <>
97
- <div>
98
- <my-component first="Stencil" middle="'Don't call me a framework'" last="JS"></my-component>
99
- </div>
100
- </>
101
- );
257
+ const [value, setValue] = useState('')
258
+
259
+ <DropiInput
260
+ label="Nombre"
261
+ value={value}
262
+ onDropiInput={(e) => setValue(e.detail)}
263
+ onDropiChange={(e) => console.log('blur:', e.detail)}
264
+ required
265
+ invalid={value.length < 3}
266
+ helperText="Mínimo 3 caracteres"
267
+ />
268
+ ```
269
+
270
+ ---
271
+
272
+ ### `<dropi-text-area>`
273
+
274
+ Área de texto multi-línea con label, contador de caracteres, validación y asociación nativa a formularios.
275
+
276
+ **Props**
277
+
278
+ | Prop | Tipo | Default | Descripción |
279
+ |---|---|---|---|
280
+ | `value` | `string` | `''` | Valor controlado |
281
+ | `label` | `string` | `''` | Label superior |
282
+ | `placeholder` | `string` | `''` | Placeholder |
283
+ | `name` | `string` | `''` | Nombre para formularios nativos |
284
+ | `inputId` | `string` | `''` | ID del textarea |
285
+ | `rows` | `number` | `4` | Número de filas visibles |
286
+ | `maxlength` | `number` | — | Longitud máxima (muestra contador) |
287
+ | `minlength` | `number` | `0` | Longitud mínima |
288
+ | `resize` | `'none' \| 'both' \| 'horizontal' \| 'vertical'` | `'vertical'` | Comportamiento de resize |
289
+ | `disabled` | `boolean` | `false` | Deshabilita el campo |
290
+ | `required` | `boolean` | `false` | Marca como requerido |
291
+ | `showAsterisk` | `boolean` | `false` | Muestra asterisco cuando `required` |
292
+ | `invalid` | `boolean` | `false` | Marca el campo como inválido |
293
+ | `helperText` | `string` | `''` | Texto de ayuda o error |
294
+
295
+ **Eventos**
296
+
297
+ | Evento | `e.detail` | Cuándo |
298
+ |---|---|---|
299
+ | `dropiInput` | `string` | En cada tecla (keystroke) |
300
+ | `dropiChange` | `string` | Al perder el foco (blur) |
301
+ | `dropiFocus` | `void` | Al enfocar el campo |
302
+ | `dropiBlur` | `void` | Al desenfocar el campo |
303
+
304
+ **Ejemplo React**
305
+ ```tsx
306
+ const [text, setText] = useState('')
307
+
308
+ <DropiTextArea
309
+ label="Descripción"
310
+ value={text}
311
+ maxlength={200}
312
+ rows={5}
313
+ onDropiInput={(e) => setText(e.detail)}
314
+ />
315
+ ```
316
+
317
+ ---
318
+
319
+ ### `<dropi-select>`
320
+
321
+ Select avanzado con búsqueda, multi-selección, opciones agrupadas, flags de países y opciones radio con imagen.
322
+
323
+ **Tipos**
324
+
325
+ ```typescript
326
+ interface SelectOption {
327
+ id: string | number
328
+ label: string
329
+ shortLabel?: string // para showCountryFlags
330
+ secondLabel?: string // subtítulo en radioOptions
331
+ countryCode?: string // código de país para flags
332
+ imageUrl?: string // imagen en radioOptions
333
+ preIcon?: string // ícono izquierdo
334
+ disabled?: boolean
102
335
  }
103
336
 
104
- export default App;
337
+ interface SelectOptionGroup {
338
+ category: string // título del grupo
339
+ options: SelectOption[]
340
+ }
341
+ ```
342
+
343
+ **Props**
344
+
345
+ | Prop | Tipo | Default | Descripción |
346
+ |---|---|---|---|
347
+ | `options` | `SelectOption[] \| SelectOptionGroup[]` | `[]` | Lista de opciones |
348
+ | `label` | `string` | `''` | Label superior |
349
+ | `placeholder` | `string` | `'Seleccionar'` | Texto sin selección |
350
+ | `name` | `string` | `''` | Nombre para formularios nativos |
351
+ | `value` | `SelectOption \| null` | `null` | Opción seleccionada (controlado) |
352
+ | `defaultSelectedId` | `string \| number` | `''` | Pre-seleccionar por id |
353
+ | `disabled` | `boolean` | `false` | Deshabilita el select |
354
+ | `invalid` | `boolean` | `false` | Estado inválido |
355
+ | `errorText` | `string` | `''` | Texto de error |
356
+ | `helperText` | `string` | `''` | Texto de ayuda |
357
+ | `showObligatory` | `boolean` | `false` | Muestra asterisco de obligatorio |
358
+ | `searchEnabled` | `boolean` | `false` | Habilita búsqueda en el dropdown |
359
+ | `multiSelect` | `boolean` | `false` | Permite múltiples selecciones |
360
+ | `dropdownType` | `boolean` | `false` | Trigger sin borde (inline) |
361
+ | `showCountryFlags` | `boolean` | `false` | Muestra flag de país |
362
+ | `radioOptions` | `boolean` | `false` | Opciones estilo radio con imagen |
363
+ | `placeHolderSearch` | `string` | `'Buscar'` | Placeholder del buscador |
364
+ | `preIcon` | `string` | `''` | Ícono antes del label del trigger |
365
+
366
+ **Métodos públicos**
367
+
368
+ | Método | Descripción |
369
+ |---|---|
370
+ | `setById(id)` | Selecciona una opción por su id |
371
+ | `setByLabel(label)` | Selecciona una opción por su label |
372
+ | `clearSelection()` | Limpia la selección actual |
373
+ | `resetMultiSelect()` | Limpia la selección múltiple |
374
+
375
+ **Eventos**
376
+
377
+ | Evento | `e.detail` | Cuándo |
378
+ |---|---|---|
379
+ | `dropiChange` | `SelectOption` (single) o `SelectOption[]` (multi) | Al seleccionar una opción |
380
+ | `dropiClear` | `void` | Al limpiar la selección |
381
+ | `dropiSearch` | `string` | Al escribir en el buscador |
382
+ | `dropiScrollEnd` | `void` | Al llegar al final del scroll (paginación) |
383
+ | `dropiKeyEnter` | `KeyboardEvent` | Al presionar Enter en el buscador |
384
+
385
+ **Ejemplo React**
386
+ ```tsx
387
+ const [selected, setSelected] = useState(null)
388
+
389
+ const options = [
390
+ { id: 1, label: 'Colombia' },
391
+ { id: 2, label: 'México' },
392
+ ]
393
+
394
+ <DropiSelect
395
+ label="País"
396
+ options={options}
397
+ searchEnabled
398
+ onDropiChange={(e) => setSelected(e.detail)}
399
+ />
105
400
  ```
106
401
 
107
- Check out this [Live Demo](https://stackblitz.com/edit/vitejs-vite-b6zuds?file=src%2FApp.tsx).# dropi-ui
402
+ ---
403
+
404
+ ### `<dropi-radio-button>`
405
+
406
+ Radio button estilizado con label y soporte para grupos.
407
+
408
+ **Props**
409
+
410
+ | Prop | Tipo | Default | Descripción |
411
+ |---|---|---|---|
412
+ | `label` | `string` | `''` | Texto del label |
413
+ | `name` | `string` | `'radio'` | Nombre para agrupar radios |
414
+ | `inputId` | `string` | `'radioButton'` | ID del input |
415
+ | `checked` | `boolean` | `false` | Estado seleccionado |
416
+ | `resetTrigger` | `boolean` | `false` | Al poner `true` resetea a desmarcado |
417
+
418
+ **Eventos**
419
+
420
+ | Evento | `e.detail` | Cuándo |
421
+ |---|---|---|
422
+ | `dropiChange` | `Event` (evento nativo) | Al seleccionar el radio |
423
+
424
+ > A diferencia del checkbox, emite el `Event` nativo. Para controlar el estado, maneja la prop `checked` desde el padre.
425
+
426
+ **Ejemplo React**
427
+ ```tsx
428
+ const [selected, setSelected] = useState('a')
429
+
430
+ <DropiRadioButton label="Opción A" name="grupo" inputId="opt-a" checked={selected === 'a'} onDropiChange={() => setSelected('a')} />
431
+ <DropiRadioButton label="Opción B" name="grupo" inputId="opt-b" checked={selected === 'b'} onDropiChange={() => setSelected('b')} />
432
+ ```
433
+
434
+ ---
435
+
436
+ ### `<dropi-badge>`
437
+
438
+ Badge de estado para cuentas o usuarios. Sin eventos.
439
+
440
+ **Props**
441
+
442
+ | Prop | Tipo | Default | Descripción |
443
+ |---|---|---|---|
444
+ | `state` | `'pending' \| 'active' \| 'canceled' \| 'frozen'` | `'pending'` | Estado a mostrar |
445
+
446
+ | State | Texto mostrado |
447
+ |---|---|
448
+ | `pending` | Pendiente |
449
+ | `active` | Activo |
450
+ | `canceled` | Cancelado |
451
+ | `frozen` | Congelado |
452
+
453
+ **Ejemplo React**
454
+ ```tsx
455
+ <DropiBadge state="active" />
456
+ <DropiBadge state="pending" />
457
+ ```
458
+
459
+ ---
460
+
461
+ ### `<dropi-tag>`
462
+
463
+ Tag/chip de color para categorías, estados o etiquetas. Sin eventos.
464
+
465
+ **Props**
466
+
467
+ | Prop | Tipo | Default | Descripción |
468
+ |---|---|---|---|
469
+ | `type` | `'primary' \| 'secondary'` | `'primary'` | `primary` = relleno, `secondary` = suave |
470
+ | `state` | `'default' \| 'success' \| 'info' \| 'warning' \| 'error' \| 'legacy'` | `'default'` | Color del tag |
471
+ | `text` | `string` | `''` | Texto del tag |
472
+ | `showIcon` | `boolean` | `false` | Mostrar ícono |
473
+ | `icon` | `string` | `''` | Nombre del ícono del sprite |
474
+
475
+ **Ejemplo React**
476
+ ```tsx
477
+ <DropiTag text="Activo" state="success" type="primary" />
478
+ <DropiTag text="Pendiente" state="warning" type="secondary" />
479
+ <DropiTag text="Error" state="error" showIcon icon="Warning-circle" />
480
+ ```
481
+
482
+ ---
483
+
484
+ ### `<dropi-icon>`
485
+
486
+ Renderiza íconos SVG desde el sprite de Dropi. Sin eventos.
487
+
488
+ **Props**
489
+
490
+ | Prop | Tipo | Default | Descripción |
491
+ |---|---|---|---|
492
+ | `name` | `string` | `''` | Nombre del ícono en el sprite (ej. `'Home'`, `'Search'`) |
493
+ | `width` | `string` | `'24px'` | Ancho (valor CSS) |
494
+ | `height` | `string` | `'24px'` | Alto (valor CSS) |
495
+ | `color` | `string` | `'currentColor'` | Hex `#ff0000`, token sin `--` (`Primary-Primary-500`), o `currentColor` |
496
+
497
+ > Requiere el sprite en `/assets/icons/symbol/svg/sprite.css.svg` de la app consumidora.
498
+
499
+ **Ejemplo React**
500
+ ```tsx
501
+ <DropiIcon name="Home" width="24px" height="24px" color="Primary-Primary-500" />
502
+ <DropiIcon name="Search" color="#333333" />
503
+ <DropiIcon name="Warning-circle" color="Error-Error-500" />
504
+ ```
505
+
506
+ ---
507
+
508
+ ## Build (desarrollo)
509
+
510
+ ```bash
511
+ npm run build # compilar
512
+ npm run start # dev con watch
513
+ npm test # unit tests
514
+ ```
@@ -163,7 +163,7 @@ if (isVite) {
163
163
  const p = path.join(projectRoot, f);
164
164
  if (!fs.existsSync(p)) continue;
165
165
  const content = fs.readFileSync(p, 'utf8');
166
- if (content.includes('@dropi/ui')) { vitePatchDone = 'ya'; break; }
166
+ if (content.includes('@dropi/ui/loader') && content.includes("exclude")) { vitePatchDone = 'ya'; break; }
167
167
  const patch = `\n optimizeDeps: {\n exclude: ['@dropi/ui/loader', '@dropi/ui'],\n },`;
168
168
  const updated = content.replace(/defineConfig\(\{/, `defineConfig({${patch}`);
169
169
  if (updated !== content) { fs.writeFileSync(p, updated, 'utf8'); vitePatchDone = true; }
@@ -197,7 +197,11 @@ Errores comunes y solución:
197
197
  - Sprite: [ruta destino] ✓
198
198
  - skipLibCheck: true ✓
199
199
 
200
- Prueba rápida:
200
+ Prueba rápida (React):
201
+ import { DropiButton } from '@dropi/ui-react'
202
+ <DropiButton text="Hola Dropi" type="default" severity="primary" size="normal" />
203
+
204
+ Prueba rápida (Angular/Vue):
201
205
  <dropi-button text="Hola Dropi" type="default" severity="primary" size="normal"></dropi-button>
202
206
  ```
203
207
 
@@ -1 +0,0 @@
1
- import{r as e,c as r,h as t}from"./p-DFz-gwFP.js";const i=class{constructor(t){e(this,t),this.dropiChange=r(this,"dropiChange")}label="";name="radio";inputId="radioButton";checked=!1;resetTrigger=!1;dropiChange;onResetTrigger(e){e&&(this.checked=!1)}handleChange(e){this.checked=e.target.checked,this.dropiChange.emit(e)}render(){return t("div",{key:"3b31699bf088bee52465981074c0aea48b6fe112",class:"dropi-radio-button"},t("label",{key:"072d19bd9c88739b849db0e264c65183eaab2132",htmlFor:this.inputId},t("input",{key:"82d1600002e9dc2795cdc5c731997742adc8e2db",id:this.inputId,type:"radio",name:this.name,checked:this.checked,onChange:e=>this.handleChange(e)}),this.label))}static get formAssociated(){return!0}static get watchers(){return{resetTrigger:[{onResetTrigger:0}]}}};i.style=":host{display:inline-block}*,*::before,*::after{box-sizing:border-box}.dropi-radio-button{display:flex;align-items:center;justify-content:flex-start;gap:20px}label{display:flex;align-items:center;gap:8px;cursor:pointer;color:var(--Gray-Gray-700, #32394d);font-size:var(--font-size-s, 12px);font-weight:var(--font-weight-regular, 400);line-height:1.5}input[type='radio']{appearance:none;width:20px;height:20px;border:2px solid var(--Gray-Gray-200, #c3c9d9);border-radius:50%;background-color:transparent;position:relative;cursor:pointer;outline:none;flex-shrink:0;display:flex;justify-content:center;align-items:center}input[type='radio']::before{content:'';position:absolute;top:3px;left:3px;width:10px;height:10px;background-color:var(--Primary-Primary-400, #f7b46f);border-radius:50%;display:none}input[type='radio']:checked{border:2px solid var(--Primary-Primary-500, #f49a3d)}input[type='radio']:checked::before{display:block}";export{i as dropi_radio_button}