@diniz/webcomponents 1.0.6 → 1.1.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/README.md +41 -0
- package/dist/assets/{checkbox-demo-page-j3Ylexv2.js → checkbox-demo-page-C-tPBGML.js} +5 -10
- package/dist/assets/{dashboard-page-DAzkVezy.js → dashboard-page-DG9XqSlN.js} +2 -2
- package/dist/assets/{date-picker-demo-DH82BhNJ.js → date-picker-demo-BFqT8vXb.js} +2 -2
- package/dist/assets/index-BiVNQ5Fp.js +343 -0
- package/dist/assets/index-DFxj0POj.css +1 -0
- package/dist/assets/input-demo-C8SDvXHc.js +113 -0
- package/dist/assets/modal-demo-page-DdQtx_aK.js +164 -0
- package/dist/assets/modal-h8khzJNk.js +36 -0
- package/dist/assets/{select-demo-page-BORrccnw.js → select-demo-page-yyBh86Yw.js} +1 -1
- package/dist/assets/table-DAobVRE7.js +12 -0
- package/dist/assets/table-demo-Dv1cyM0s.js +74 -0
- package/dist/assets/tabs-demo-BZZ6mTYB.js +68 -0
- package/dist/index.html +25 -4
- package/package.json +4 -4
- package/dist/assets/app-layout-Dq81XbRZ.js +0 -37
- package/dist/assets/index-CzQ41fnj.js +0 -2
- package/dist/assets/index-uHZenGtA.css +0 -1
- package/dist/assets/input-demo-CzyQGRhV.js +0 -113
- package/dist/assets/modal-demo-page-C8gJP8BA.js +0 -199
- package/dist/assets/table-CSpGgpLR.js +0 -12
- package/dist/assets/table-demo-xve_6QOI.js +0 -67
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
var f=Object.defineProperty;var y=(s,a,t)=>a in s?f(s,a,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[a]=t;var n=(s,a,t)=>y(s,typeof a!="symbol"?a+"":a,t);import{B as v,t as E}from"./index-BiVNQ5Fp.js";import"./vendor-BvJLUv9i.js";class x extends v{constructor(){super();n(this,"inputEl",null);n(this,"customValidator",null);n(this,"validationRule",null);this.state={value:"",valid:!0,touched:!1,error:""}}static get observedAttributes(){return["type","label","placeholder","required","pattern","minlength","maxlength","min","max","error-message","custom-error","disabled","name","validate"]}connectedCallback(){this.setAttribute("data-ui","input"),super.connectedCallback()}attributeChangedCallback(t,e,i){e!==i&&t!=="value"&&this.render()}setCustomValidator(t){this.customValidator=t,this.validate()}get value(){return this.state.value}set value(t){this.state.value=t,this.inputEl&&this.inputEl.value!==t&&(this.inputEl.value=t),this.validate()}get isValid(){return this.state.valid}checkValidity(){return this.state.touched=!0,this.validate()}reportValidity(){this.state.touched=!0;const t=this.validate();return this.updateErrorDisplay(),!t&&this.inputEl&&this.inputEl.focus(),t}getType(){const t=this.getAttribute("type");return["text","email","password","number","tel","url"].includes(t||"")?t:"text"}getLabel(){return this.getAttribute("label")||""}getPlaceholder(){return this.getAttribute("placeholder")||""}getName(){return this.getAttribute("name")||""}getErrorMessage(){return this.state.error?this.state.error:this.getAttribute("error-message")||this.getAttribute("custom-error")||""}getCustomError(){return this.getAttribute("custom-error")||""}parseValidationRule(t){return t.startsWith("email:")?{type:"emailDomain",domain:t.slice(6)}:t.startsWith("match:")?{type:"match",selector:t.slice(6)}:t.startsWith("min:")?{type:"minLength",length:parseInt(t.slice(4),10)}:t.startsWith("max:")?{type:"maxLength",length:parseInt(t.slice(4),10)}:t.startsWith("regex:")?{type:"regex",pattern:t.slice(6)}:null}applyValidationRule(t){const e=this.state.value;switch(t.type){case"emailDomain":if(!e.endsWith(`@${t.domain}`))return{valid:!1,message:`Must end with @${t.domain}`};break;case"match":const i=document.querySelector(t.selector);if(i&&e!==i.value)return{valid:!1,message:"Values do not match"};break;case"minLength":if(e.length<t.length)return{valid:!1,message:`Must be at least ${t.length} characters`};break;case"maxLength":if(e.length>t.length)return{valid:!1,message:`Must be no more than ${t.length} characters`};break;case"regex":try{if(!new RegExp(t.pattern).test(e))return{valid:!1,message:"Invalid format"}}catch{return{valid:!1,message:"Invalid validation pattern"}}break}return{valid:!0}}validate(){if(!this.inputEl)return!0;const t=this.getAttribute("validate");if(t&&(this.validationRule||(this.validationRule=this.parseValidationRule(t)),this.validationRule)){const e=this.applyValidationRule(this.validationRule);return this.state.valid=e.valid,!e.valid&&e.message&&(this.state.error=e.message),this.state.valid}if(this.customValidator){const e=this.customValidator(this.state.value,this.inputEl);this.state.valid=e.valid,!e.valid&&e.message&&(this.state.error=e.message)}else{const e=this.inputEl.checkValidity();this.state.valid=e,!e&&this.state.touched&&(this.state.error=this.inputEl.validationMessage||this.getErrorMessage()),e&&(this.state.error="")}return this.state.valid}handleInput(t){const e=t.target;this.state.value=e.value,this.state.touched=!0,this.validate(),this.updateErrorDisplay()}handleBlur(){this.state.touched=!0,this.validate(),this.updateErrorDisplay()}updateErrorDisplay(){if(!this.inputEl)return;const t=this.shadowRoot.querySelector(".input-error"),e=this.shadowRoot.querySelector(".input-wrapper"),i=this.getName();e&&e.classList.toggle("invalid",!this.state.valid&&this.state.touched),t&&(!this.state.valid&&this.state.touched&&this.state.error?(t.textContent=this.state.error,t.classList.remove("hidden")):t.classList.add("hidden")),this.inputEl.setAttribute("aria-invalid",String(!this.state.valid&&this.state.touched)),i&&this.inputEl.setAttribute("aria-describedby",`${i}-error`)}needsRender(){return this.hasAttribute("type")||this.hasAttribute("label")||this.hasAttribute("placeholder")||this.hasAttribute("required")||this.hasAttribute("pattern")||this.hasAttribute("disabled")||this.hasAttribute("name")||this.hasAttribute("minlength")||this.hasAttribute("maxlength")||this.hasAttribute("min")||this.hasAttribute("max")||this.hasAttribute("error-message")||this.hasAttribute("custom-error")||this.hasAttribute("validate")}render(){const t=this.getType(),e=this.getLabel(),i=this.getPlaceholder(),r=this.getName(),l=this.getErrorMessage(),u=this.hasAttribute("required"),d=this.getAttribute("pattern"),h=this.getAttribute("minlength"),m=this.getAttribute("maxlength"),c=this.getAttribute("min"),p=this.getAttribute("max"),g=this.hasAttribute("disabled"),o=!this.state.valid&&this.state.touched,b=e!=="";this.shadowRoot.innerHTML=`
|
|
2
|
+
<style>${E}</style>
|
|
3
|
+
<div class="input-wrapper${o?" invalid":""}${g?" disabled":""}">
|
|
4
|
+
${b?`<label class="input-label">${e}${u?" *":""}</label>`:""}
|
|
5
|
+
<input
|
|
6
|
+
part="input"
|
|
7
|
+
class="input-field"
|
|
8
|
+
type="${t}"
|
|
9
|
+
placeholder="${i}"
|
|
10
|
+
name="${r}"
|
|
11
|
+
.value="${this.state.value}"
|
|
12
|
+
${u?"required":""}
|
|
13
|
+
${d?`pattern="${d}"`:""}
|
|
14
|
+
${h?`minlength="${h}"`:""}
|
|
15
|
+
${m?`maxlength="${m}"`:""}
|
|
16
|
+
${c?`min="${c}"`:""}
|
|
17
|
+
${p?`max="${p}"`:""}
|
|
18
|
+
${g?"disabled":""}
|
|
19
|
+
aria-invalid="${o}"
|
|
20
|
+
aria-describedby="${r}-error"
|
|
21
|
+
/>
|
|
22
|
+
<span class="input-error${o&&l?"":" hidden"}" id="${r}-error" role="alert">${l}</span>
|
|
23
|
+
</div>
|
|
24
|
+
`,this.inputEl=this.shadowRoot.querySelector(".input-field"),this.inputEl&&(this.inputEl.addEventListener("input",this.handleInput.bind(this)),this.inputEl.addEventListener("blur",this.handleBlur.bind(this)))}}customElements.define("ui-input",x);const A=`<div class="demo-container">
|
|
25
|
+
<h1>Input Component Demo</h1>
|
|
26
|
+
<p class="demo-description">
|
|
27
|
+
Explore the <code><ui-input></code> component with various validation scenarios.
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
<section class="demo-section">
|
|
31
|
+
<h2>Basic Inputs</h2>
|
|
32
|
+
<div class="form-grid">
|
|
33
|
+
<ui-input
|
|
34
|
+
label="Username"
|
|
35
|
+
placeholder="Enter your username"
|
|
36
|
+
name="username"
|
|
37
|
+
required
|
|
38
|
+
minlength="3"
|
|
39
|
+
maxlength="20"
|
|
40
|
+
></ui-input>
|
|
41
|
+
|
|
42
|
+
<ui-input
|
|
43
|
+
label="Email"
|
|
44
|
+
type="email"
|
|
45
|
+
placeholder="you@example.com"
|
|
46
|
+
name="email"
|
|
47
|
+
required
|
|
48
|
+
></ui-input>
|
|
49
|
+
|
|
50
|
+
<ui-input
|
|
51
|
+
label="Password"
|
|
52
|
+
type="password"
|
|
53
|
+
placeholder="Enter password"
|
|
54
|
+
name="password"
|
|
55
|
+
required
|
|
56
|
+
minlength="8"
|
|
57
|
+
></ui-input>
|
|
58
|
+
|
|
59
|
+
<ui-input
|
|
60
|
+
label="Phone"
|
|
61
|
+
type="tel"
|
|
62
|
+
placeholder="(555) 123-4567"
|
|
63
|
+
name="phone"
|
|
64
|
+
pattern="[0-9\\-\\(\\)\\s]+"
|
|
65
|
+
></ui-input>
|
|
66
|
+
</div>
|
|
67
|
+
</section>
|
|
68
|
+
|
|
69
|
+
<section class="demo-section">
|
|
70
|
+
<h2>Custom Validation</h2>
|
|
71
|
+
<p>Email must end with <code>@company.com</code></p>
|
|
72
|
+
<div class="form-grid">
|
|
73
|
+
<ui-input
|
|
74
|
+
label="Corporate Email"
|
|
75
|
+
type="email"
|
|
76
|
+
placeholder="you@company.com"
|
|
77
|
+
name="corp-email"
|
|
78
|
+
required
|
|
79
|
+
validate="email:company.com"
|
|
80
|
+
custom-error="Must be a company.com email"
|
|
81
|
+
id="corp-email"
|
|
82
|
+
></ui-input>
|
|
83
|
+
|
|
84
|
+
<ui-input
|
|
85
|
+
label="Confirm Email"
|
|
86
|
+
type="email"
|
|
87
|
+
placeholder="Confirm your email"
|
|
88
|
+
name="confirm-email"
|
|
89
|
+
required
|
|
90
|
+
validate="match:#corp-email"
|
|
91
|
+
custom-error="Emails must match"
|
|
92
|
+
id="confirm-email"
|
|
93
|
+
></ui-input>
|
|
94
|
+
</div>
|
|
95
|
+
</section>
|
|
96
|
+
|
|
97
|
+
<section class="demo-section">
|
|
98
|
+
<h2>Disabled State</h2>
|
|
99
|
+
<div class="form-grid">
|
|
100
|
+
<ui-input
|
|
101
|
+
label="Disabled Input"
|
|
102
|
+
placeholder="Cannot edit"
|
|
103
|
+
name="disabled"
|
|
104
|
+
value="This is disabled"
|
|
105
|
+
disabled
|
|
106
|
+
></ui-input>
|
|
107
|
+
</div>
|
|
108
|
+
</section>
|
|
109
|
+
</div>
|
|
110
|
+
`,$=".demo-container{padding:2rem;max-width:800px}.demo-container h1{margin:0 0 .5rem;color:var(--color-ink)}.demo-description{color:#64748b;margin-bottom:2rem}.demo-description code{background:var(--color-muted);padding:.15rem .4rem;border-radius:4px;font-size:.9em}.demo-section{margin-bottom:2.5rem;padding:1.5rem;background:var(--color-page-bg);border:1px solid var(--color-border);border-radius:var(--radius-md)}.demo-section h2{margin:0 0 1rem;font-size:1.25rem;color:var(--color-ink)}.demo-section>p{margin:0 0 1rem;color:#64748b}.form-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1.25rem}.form-actions{margin-top:1.5rem;display:flex;gap:.75rem}.demo-form{margin-bottom:1rem}.form-result{margin-top:1rem;padding:.75rem 1rem;background:var(--color-muted);border-radius:6px;display:flex;gap:.5rem}.result-label{font-weight:600;color:var(--color-ink)}.result-value{color:#64748b}.result-value.valid{color:#24ec71}.result-value.invalid{color:#ef4444}";class w extends v{constructor(){super(...arguments);n(this,"formResult",null);n(this,"statusSpan",null)}render(){this.shadowRoot.innerHTML=`
|
|
111
|
+
<style>${$}</style>
|
|
112
|
+
${A}
|
|
113
|
+
`,this.formResult=this.shadowRoot.querySelector("#form-result"),this.statusSpan=this.shadowRoot.querySelector("#result-status");const t=this.shadowRoot.querySelector("#demo-form"),e=this.shadowRoot.querySelector("#reset-btn");t&&t.addEventListener("submit",this.handleSubmit.bind(this)),e&&e.addEventListener("click",this.handleReset.bind(this))}async handleSubmit(t){t.preventDefault();const e=Array.from(this.shadowRoot.querySelectorAll("ui-input"));let i=!0;for(const r of e)r.reportValidity()||(i=!1);this.statusSpan&&(this.statusSpan.textContent=i?"Valid":"Invalid",this.statusSpan.className=`result-value ${i?"valid":"invalid"}`)}handleReset(){this.shadowRoot.querySelectorAll("ui-input").forEach(e=>{e.value=""}),this.statusSpan&&(this.statusSpan.textContent="Not validated",this.statusSpan.className="result-value")}}customElements.define("input-demo",w);export{w as InputDemo};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import{B as w}from"./index-BiVNQ5Fp.js";import"./modal-h8khzJNk.js";import"./vendor-BvJLUv9i.js";const B=`
|
|
2
|
+
<div class="demo-container">
|
|
3
|
+
<h1>Modal Component Demo</h1>
|
|
4
|
+
<p>Interactive modals with various sizes and configurations.</p>
|
|
5
|
+
|
|
6
|
+
<div class="demo-section">
|
|
7
|
+
<h2>Basic Modals</h2>
|
|
8
|
+
<div class="demo-controls">
|
|
9
|
+
<ui-button id="openBasicModal" variant="primary" icon="maximize-2">
|
|
10
|
+
Open Basic Modal
|
|
11
|
+
</ui-button>
|
|
12
|
+
<ui-button id="openSmallModal" variant="secondary">
|
|
13
|
+
Small Modal
|
|
14
|
+
</ui-button>
|
|
15
|
+
<ui-button id="openLargeModal" variant="secondary">
|
|
16
|
+
Large Modal
|
|
17
|
+
</ui-button>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div class="demo-section">
|
|
22
|
+
<h2>Modal Behaviors</h2>
|
|
23
|
+
<div class="demo-controls">
|
|
24
|
+
<ui-button id="openNoEscapeModal" variant="ghost">
|
|
25
|
+
No Close on Escape
|
|
26
|
+
</ui-button>
|
|
27
|
+
<ui-button id="openNoBackdropModal" variant="ghost">
|
|
28
|
+
No Close on Backdrop
|
|
29
|
+
</ui-button>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="demo-section">
|
|
34
|
+
<h2>Confirmation Modal</h2>
|
|
35
|
+
<div class="demo-controls">
|
|
36
|
+
<ui-button id="openConfirmModal" variant="primary" icon="alert-circle">
|
|
37
|
+
Delete Item
|
|
38
|
+
</ui-button>
|
|
39
|
+
</div>
|
|
40
|
+
<div id="confirmResult" class="result-display" style="display: none;">
|
|
41
|
+
<strong>Result:</strong> <span id="confirmText"></span>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<!-- Modals -->
|
|
46
|
+
<ui-modal id="basicModal" title="Welcome!" size="md">
|
|
47
|
+
<p>This is a basic modal with a title and content.</p>
|
|
48
|
+
<p>You can close it by:</p>
|
|
49
|
+
<ul>
|
|
50
|
+
<li>Clicking the X button</li>
|
|
51
|
+
<li>Pressing the Escape key</li>
|
|
52
|
+
<li>Clicking outside the modal</li>
|
|
53
|
+
</ul>
|
|
54
|
+
<div slot="footer">
|
|
55
|
+
<ui-button id="basicModalClose" variant="secondary">Close</ui-button>
|
|
56
|
+
<ui-button id="basicModalOk" variant="primary">Got it!</ui-button>
|
|
57
|
+
</div>
|
|
58
|
+
</ui-modal>
|
|
59
|
+
|
|
60
|
+
<ui-modal id="smallModal" title="Small Modal" size="sm">
|
|
61
|
+
<p>This is a small modal perfect for quick messages or confirmations.</p>
|
|
62
|
+
<div slot="footer">
|
|
63
|
+
<ui-button id="smallModalClose" variant="primary">Close</ui-button>
|
|
64
|
+
</div>
|
|
65
|
+
</ui-modal>
|
|
66
|
+
|
|
67
|
+
<ui-modal id="largeModal" title="Large Modal" size="lg">
|
|
68
|
+
<p>This is a large modal that can contain more content.</p>
|
|
69
|
+
<div style="height: 400px; background: #f1f5f9; border-radius: 8px; padding: 1rem; margin: 1rem 0;">
|
|
70
|
+
<p><strong>Scrollable Content Area</strong></p>
|
|
71
|
+
<p>When content exceeds the modal height, it automatically becomes scrollable.</p>
|
|
72
|
+
${Array(20).fill("<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>").join("")}
|
|
73
|
+
</div>
|
|
74
|
+
<div slot="footer">
|
|
75
|
+
<ui-button id="largeModalClose" variant="primary">Close</ui-button>
|
|
76
|
+
</div>
|
|
77
|
+
</ui-modal>
|
|
78
|
+
|
|
79
|
+
<ui-modal id="noEscapeModal" title="No Escape Close" size="md" no-close-on-escape>
|
|
80
|
+
<p>This modal cannot be closed by pressing the Escape key.</p>
|
|
81
|
+
<p>You must click the close button or click outside.</p>
|
|
82
|
+
<div slot="footer">
|
|
83
|
+
<ui-button id="noEscapeClose" variant="primary">Close</ui-button>
|
|
84
|
+
</div>
|
|
85
|
+
</ui-modal>
|
|
86
|
+
|
|
87
|
+
<ui-modal id="noBackdropModal" title="No Backdrop Close" size="md" no-close-on-backdrop>
|
|
88
|
+
<p>This modal cannot be closed by clicking the backdrop.</p>
|
|
89
|
+
<p>You must use the close button or press Escape.</p>
|
|
90
|
+
<div slot="footer">
|
|
91
|
+
<ui-button id="noBackdropClose" variant="primary">Close</ui-button>
|
|
92
|
+
</div>
|
|
93
|
+
</ui-modal>
|
|
94
|
+
|
|
95
|
+
<ui-modal id="confirmModal" title="Confirm Delete" size="sm">
|
|
96
|
+
<p>Are you sure you want to delete this item?</p>
|
|
97
|
+
<p style="color: #ef4444; font-size: 0.875rem;">This action cannot be undone.</p>
|
|
98
|
+
<div slot="footer">
|
|
99
|
+
<ui-button id="confirmCancel" variant="ghost">Cancel</ui-button>
|
|
100
|
+
<ui-button id="confirmDelete" variant="primary" icon="trash-2">Delete</ui-button>
|
|
101
|
+
</div>
|
|
102
|
+
</ui-modal>
|
|
103
|
+
</div>
|
|
104
|
+
`,C=`
|
|
105
|
+
.demo-container {
|
|
106
|
+
padding: 2rem;
|
|
107
|
+
max-width: 1200px;
|
|
108
|
+
margin: 0 auto;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.demo-container h1 {
|
|
112
|
+
font-size: 2rem;
|
|
113
|
+
margin-bottom: 0.5rem;
|
|
114
|
+
color: var(--color-ink);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.demo-container > p {
|
|
118
|
+
color: var(--color-text-muted);
|
|
119
|
+
margin-bottom: 2rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.demo-section {
|
|
123
|
+
margin-bottom: 3rem;
|
|
124
|
+
padding-bottom: 2rem;
|
|
125
|
+
border-bottom: 1px solid var(--color-border);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.demo-section:last-child {
|
|
129
|
+
border-bottom: none;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.demo-section h2 {
|
|
133
|
+
font-size: 1.5rem;
|
|
134
|
+
margin-bottom: 1rem;
|
|
135
|
+
color: var(--color-ink);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.demo-controls {
|
|
139
|
+
display: flex;
|
|
140
|
+
gap: 1rem;
|
|
141
|
+
flex-wrap: wrap;
|
|
142
|
+
margin-top: 1rem;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.result-display {
|
|
146
|
+
margin-top: 1rem;
|
|
147
|
+
padding: 1rem;
|
|
148
|
+
background: var(--color-muted);
|
|
149
|
+
border-radius: var(--radius-md);
|
|
150
|
+
border-left: 4px solid var(--color-primary);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
ul {
|
|
154
|
+
margin: 1rem 0;
|
|
155
|
+
padding-left: 1.5rem;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
li {
|
|
159
|
+
margin: 0.5rem 0;
|
|
160
|
+
}
|
|
161
|
+
`;class R extends w{async connectedCallback(){super.connectedCallback(),await Promise.all([customElements.whenDefined("ui-modal"),customElements.whenDefined("ui-button")]),await new Promise(a=>setTimeout(a,10)),this.setupEventListeners()}setupEventListeners(){const a=this.shadowRoot.getElementById("openBasicModal"),o=this.shadowRoot.getElementById("basicModal"),r=this.shadowRoot.getElementById("basicModalClose"),c=this.shadowRoot.getElementById("basicModalOk");a==null||a.addEventListener("click",()=>o==null?void 0:o.open()),r==null||r.addEventListener("click",()=>o==null?void 0:o.close()),c==null||c.addEventListener("click",()=>o==null?void 0:o.close());const m=this.shadowRoot.getElementById("openSmallModal"),e=this.shadowRoot.getElementById("smallModal"),u=this.shadowRoot.getElementById("smallModalClose");m==null||m.addEventListener("click",()=>e==null?void 0:e.open()),u==null||u.addEventListener("click",()=>e==null?void 0:e.close());const p=this.shadowRoot.getElementById("openLargeModal"),i=this.shadowRoot.getElementById("largeModal"),h=this.shadowRoot.getElementById("largeModalClose");p==null||p.addEventListener("click",()=>i==null?void 0:i.open()),h==null||h.addEventListener("click",()=>i==null?void 0:i.close());const v=this.shadowRoot.getElementById("openNoEscapeModal"),n=this.shadowRoot.getElementById("noEscapeModal"),g=this.shadowRoot.getElementById("noEscapeClose");v==null||v.addEventListener("click",()=>n==null?void 0:n.open()),g==null||g.addEventListener("click",()=>n==null?void 0:n.close());const b=this.shadowRoot.getElementById("openNoBackdropModal"),s=this.shadowRoot.getElementById("noBackdropModal"),y=this.shadowRoot.getElementById("noBackdropClose");b==null||b.addEventListener("click",()=>s==null?void 0:s.open()),y==null||y.addEventListener("click",()=>s==null?void 0:s.close());const E=this.shadowRoot.getElementById("openConfirmModal"),t=this.shadowRoot.getElementById("confirmModal"),f=this.shadowRoot.getElementById("confirmCancel"),k=this.shadowRoot.getElementById("confirmDelete"),l=this.shadowRoot.getElementById("confirmResult"),d=this.shadowRoot.getElementById("confirmText");E==null||E.addEventListener("click",()=>t==null?void 0:t.open()),f==null||f.addEventListener("click",()=>{t==null||t.close(),l&&d&&(l.style.display="block",d.textContent="Cancelled",d.style.color="#64748b")}),k==null||k.addEventListener("click",()=>{t==null||t.close(),l&&d&&(l.style.display="block",d.textContent="Item deleted!",d.style.color="#ef4444")})}render(){this.shadowRoot.innerHTML=`
|
|
162
|
+
<style>${C}</style>
|
|
163
|
+
${B}
|
|
164
|
+
`}}customElements.define("modal-demo-page",R);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
var c=Object.defineProperty;var r=(s,e,t)=>e in s?c(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var d=(s,e,t)=>r(s,typeof e!="symbol"?e+"":e,t);import{B as h,t as p}from"./index-BiVNQ5Fp.js";class u extends h{constructor(){super(...arguments);d(this,"isOpen",this.useSignal(!1))}connectedCallback(){this.setAttribute("data-ui","modal"),super.connectedCallback(),this.setupEventListeners()}static get observedAttributes(){return["open"]}attributeChangedCallback(t,o,i){t==="open"&&o!==i&&this.isOpen.set(i!==null)}setupEventListeners(){document.addEventListener("keydown",t=>{t.key==="Escape"&&this.isOpen.get()&&!this.hasAttribute("no-close-on-escape")&&this.close()})}open(){this.isOpen.set(!0),this.setAttribute("open",""),this.dispatchEvent(new CustomEvent("modal-open",{bubbles:!0,composed:!0})),document.body.style.overflow="hidden"}close(){this.isOpen.set(!1),this.removeAttribute("open"),this.dispatchEvent(new CustomEvent("modal-close",{bubbles:!0,composed:!0})),document.body.style.overflow=""}handleBackdropClick(t){t.target.classList.contains("modal-backdrop")&&!this.hasAttribute("no-close-on-backdrop")&&this.close()}render(){const t=this.isOpen.get(),o=this.getAttribute("title")||"",i=this.getAttribute("size")||"md";this.shadowRoot.innerHTML=`
|
|
2
|
+
<style>
|
|
3
|
+
${p}
|
|
4
|
+
|
|
5
|
+
::slotted([slot="footer"]) {
|
|
6
|
+
display: flex;
|
|
7
|
+
gap: 0.75rem;
|
|
8
|
+
width: 100%;
|
|
9
|
+
justify-content: flex-end;
|
|
10
|
+
}
|
|
11
|
+
</style>
|
|
12
|
+
|
|
13
|
+
<div class="modal-backdrop ${t?"open":""}" part="backdrop">
|
|
14
|
+
<div class="modal-content ${i}" part="content" @click="${a=>a.stopPropagation()}">
|
|
15
|
+
${o?`
|
|
16
|
+
<div class="modal-header" part="header">
|
|
17
|
+
<h2 class="modal-title">${o}</h2>
|
|
18
|
+
<button class="modal-close" part="close" aria-label="Close modal">
|
|
19
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
20
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
21
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
22
|
+
</svg>
|
|
23
|
+
</button>
|
|
24
|
+
</div>
|
|
25
|
+
`:""}
|
|
26
|
+
|
|
27
|
+
<div class="modal-body" part="body">
|
|
28
|
+
<slot></slot>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="modal-footer" part="footer">
|
|
32
|
+
<slot name="footer"></slot>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
`;const l=this.shadowRoot.querySelector(".modal-backdrop"),n=this.shadowRoot.querySelector(".modal-close");l==null||l.addEventListener("click",a=>this.handleBackdropClick(a)),n==null||n.addEventListener("click",()=>this.close())}}customElements.define("ui-modal",u);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var w=Object.defineProperty;var E=(c,l,e)=>l in c?w(c,l,{enumerable:!0,configurable:!0,writable:!0,value:e}):c[l]=e;var m=(c,l,e)=>E(c,typeof l!="symbol"?l+"":l,e);import{B as y,
|
|
1
|
+
var w=Object.defineProperty;var E=(c,l,e)=>l in c?w(c,l,{enumerable:!0,configurable:!0,writable:!0,value:e}):c[l]=e;var m=(c,l,e)=>E(c,typeof l!="symbol"?l+"":l,e);import{B as y,t as R}from"./index-BiVNQ5Fp.js";import"./vendor-BvJLUv9i.js";const k=`
|
|
2
2
|
<div class="demo-container">
|
|
3
3
|
<h1>Select Component Demo</h1>
|
|
4
4
|
<p>Customizable dropdown select with search and multi-configuration options.</p>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
var h=Object.defineProperty;var u=(i,e,t)=>e in i?h(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var o=(i,e,t)=>u(i,typeof e!="symbol"?e+"":e,t);import{B as m,t as w}from"./index-BiVNQ5Fp.js";class $ extends m{constructor(){super(...arguments);o(this,"columns",[]);o(this,"rows",[])}connectedCallback(){this.setAttribute("data-ui","table"),super.connectedCallback()}set data(t){this.columns=t.columns,this.rows=t.rows,this.render()}get data(){return{columns:this.columns,rows:this.rows}}render(){const t=this.columns.filter(a=>a.visible!==!1),d=t.map(a=>`<th class="align-${a.align??"left"}">${a.label}</th>`).join(""),l=this.rows.map((a,n)=>`<tr data-row-index="${n}">${t.map(s=>s.actions?`<td class="align-center actions-cell">
|
|
2
|
+
${s.actions.edit?`<ui-button variant="primary" class='action-btn' icon='edit' size="sm" data-action="edit" data-row-index="${n}">Edit</ui-button>`:""}
|
|
3
|
+
${s.actions.delete?`<ui-button variant="danger" class='action-btn' icon='trash' size="sm" data-action="delete" data-row-index="${n}">Delete</ui-button>`:""}
|
|
4
|
+
</td>`:`<td class="align-${s.align??"left"}">${String(a[s.key]??"")}</td>`).join("")}</tr>`).join("");this.shadowRoot.innerHTML=`
|
|
5
|
+
<style>${w}</style>
|
|
6
|
+
<div class="table-wrap">
|
|
7
|
+
<table>
|
|
8
|
+
<thead><tr>${d}</tr></thead>
|
|
9
|
+
<tbody>${l}</tbody>
|
|
10
|
+
</table>
|
|
11
|
+
</div>
|
|
12
|
+
`,this.shadowRoot.querySelectorAll(".action-btn").forEach(a=>{a.addEventListener("click",n=>{const s=n.currentTarget,c=s.dataset.action,r=parseInt(s.dataset.rowIndex||"0",10),b=c==="edit"?"edit-action":"delete-action";this.dispatchEvent(new CustomEvent(b,{bubbles:!0,composed:!0,detail:{row:this.rows[r],rowIndex:r}}))})})}}customElements.define("ui-table",$);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
var m=Object.defineProperty;var b=(c,r,t)=>r in c?m(c,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):c[r]=t;var n=(c,r,t)=>b(c,typeof r!="symbol"?r+"":r,t);import{B as p,t as f}from"./index-BiVNQ5Fp.js";import"./table-DAobVRE7.js";import"./modal-h8khzJNk.js";import"./vendor-BvJLUv9i.js";class k extends p{constructor(){super(...arguments);n(this,"_total",0);n(this,"_currentPage",1);n(this,"_pageSize",10)}connectedCallback(){this.setAttribute("data-ui","pagination"),super.connectedCallback()}static get observedAttributes(){return["total","current-page","page-size"]}attributeChangedCallback(t,e,a){switch(t){case"total":this._total=parseInt(a,10)||0;break;case"current-page":this._currentPage=parseInt(a,10)||1;break;case"page-size":this._pageSize=parseInt(a,10)||10;break}this.render()}get total(){return this._total}set total(t){this._total=t,this.setAttribute("total",String(t))}get currentPage(){return this._currentPage}set currentPage(t){this._currentPage=t,this.setAttribute("current-page",String(t))}get pageSize(){return this._pageSize}set pageSize(t){this._pageSize=t,this.setAttribute("page-size",String(t))}get totalPages(){return Math.ceil(this._total/this._pageSize)}handlePageChange(t){t<1||t>this.totalPages||t===this._currentPage||(this.currentPage=t,this.dispatchEvent(new CustomEvent("page-change",{detail:{page:t,pageSize:this._pageSize,total:this._total,totalPages:this.totalPages},bubbles:!0,composed:!0})))}getPageNumbers(){const t=this.totalPages,e=this._currentPage;if(t<=7)return Array.from({length:t},(s,o)=>o+1);const a=[];return e<=3?a.push(1,2,3,4,"...",t):e>=t-2?a.push(1,"...",t-3,t-2,t-1,t):a.push(1,"...",e-1,e,e+1,"...",t),a}render(){const t=this.totalPages,e=this._currentPage,a=this.getPageNumbers(),s=(e-1)*this._pageSize+1,o=Math.min(e*this._pageSize,this._total);this.shadowRoot.innerHTML=`
|
|
2
|
+
<style>${f}</style>
|
|
3
|
+
<div class="pagination-container">
|
|
4
|
+
<div class="pagination-info">
|
|
5
|
+
${this._total>0?`Showing ${s} to ${o} of ${this._total}`:"No results"}
|
|
6
|
+
</div>
|
|
7
|
+
${t>1?`
|
|
8
|
+
<nav class="pagination" role="navigation" aria-label="Pagination">
|
|
9
|
+
<button
|
|
10
|
+
class="page-btn nav-btn"
|
|
11
|
+
${e===1?"disabled":""}
|
|
12
|
+
data-page="prev"
|
|
13
|
+
aria-label="Previous page"
|
|
14
|
+
>
|
|
15
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
16
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
|
17
|
+
</svg>
|
|
18
|
+
</button>
|
|
19
|
+
${a.map(i=>i==="..."?'<button class="page-btn ellipsis" disabled>...</button>':`
|
|
20
|
+
<button
|
|
21
|
+
class="page-btn ${i===e?"active":""}"
|
|
22
|
+
data-page="${i}"
|
|
23
|
+
aria-label="Page ${i}"
|
|
24
|
+
${i===e?'aria-current="page"':""}
|
|
25
|
+
>
|
|
26
|
+
${i}
|
|
27
|
+
</button>
|
|
28
|
+
`).join("")}
|
|
29
|
+
<button
|
|
30
|
+
class="page-btn nav-btn"
|
|
31
|
+
${e===t?"disabled":""}
|
|
32
|
+
data-page="next"
|
|
33
|
+
aria-label="Next page"
|
|
34
|
+
>
|
|
35
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
36
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
|
37
|
+
</svg>
|
|
38
|
+
</button>
|
|
39
|
+
</nav>
|
|
40
|
+
`:""}
|
|
41
|
+
</div>
|
|
42
|
+
`,this.attachEventListeners()}attachEventListeners(){this.shadowRoot&&this.shadowRoot.addEventListener("click",t=>{const a=t.target.closest(".page-btn");if(!a||a.disabled)return;const s=a.dataset.page;if(s==="prev")this.handlePageChange(this._currentPage-1);else if(s==="next")this.handlePageChange(this._currentPage+1);else if(s){const o=parseInt(s,10);isNaN(o)||this.handlePageChange(o)}})}}customElements.define("ui-pagination",k);const v=`<h1>Table Demo</h1>\r
|
|
43
|
+
<p class="intro">Example of loading JSON data and rendering a table.</p>\r
|
|
44
|
+
\r
|
|
45
|
+
<div class="demo-section">\r
|
|
46
|
+
<div class="section-header">\r
|
|
47
|
+
<h2>Data Source</h2>\r
|
|
48
|
+
<span class="status" id="data-status">Loading...</span>\r
|
|
49
|
+
</div>\r
|
|
50
|
+
<div class="code-block">\r
|
|
51
|
+
<code>fetch('https://dummyjson.com/products')</code>\r
|
|
52
|
+
</div>\r
|
|
53
|
+
</div>\r
|
|
54
|
+
\r
|
|
55
|
+
<div class="demo-section">\r
|
|
56
|
+
<h2>Table</h2>\r
|
|
57
|
+
<div class="action-message" id="action-message" style="display: none;"></div>\r
|
|
58
|
+
<ui-table id="demo-table"></ui-table>\r
|
|
59
|
+
<div class="meta" id="data-meta"></div>\r
|
|
60
|
+
<ui-pagination></ui-pagination>\r
|
|
61
|
+
</div>\r
|
|
62
|
+
\r
|
|
63
|
+
\r
|
|
64
|
+
<ui-modal id="confirmModal" title="Confirm Delete" size="sm">\r
|
|
65
|
+
<p>Are you sure you want to delete this item?</p>\r
|
|
66
|
+
<p style="color: #ef4444; font-size: 0.875rem;">This action cannot be undone.</p>\r
|
|
67
|
+
<div slot="footer">\r
|
|
68
|
+
<ui-button id="confirmCancel" variant="ghost">Cancel</ui-button>\r
|
|
69
|
+
<ui-button id="confirmDelete" variant="primary" icon="trash-2">Delete</ui-button>\r
|
|
70
|
+
</div>\r
|
|
71
|
+
</ui-modal>`,y=":host{display:block;padding:2rem;max-width:1200px;margin:0 auto}.intro{color:var(--color-ink, #0f172a);opacity:.8;margin-bottom:1.5rem}h1{font-size:2rem;margin-bottom:.5rem;color:var(--color-ink, #0f172a)}h2{font-size:1.4rem;margin-top:0;margin-bottom:.75rem;color:var(--color-ink, #0f172a)}.demo-section{margin-bottom:2rem;padding:1.5rem;border:1px solid #e2e8f0;border-radius:12px;background:#fff}.section-header{display:flex;align-items:center;justify-content:space-between;gap:1rem}.status{font-size:.85rem;font-weight:600;padding:.25rem .6rem;border-radius:999px;background:#e2e8f0;color:#334155}.status.loading{background:#fde68a;color:#92400e}.status.success{background:#bbf7d0;color:#166534}.status.error{background:#fecaca;color:#b91c1c}.code-block{background:#f1f5f9;padding:1rem;border-radius:8px;overflow-x:auto}code{font-family:Courier New,monospace;font-size:.9rem;color:#334155}.meta{margin-top:.75rem;margin-bottom:.75rem;font-size:.85rem;color:#64748b}ui-pagination{margin-top:1rem}.json-output{margin:0;background:#0f172a;color:#e2e8f0;padding:1rem;border-radius:8px;overflow-x:auto;font-size:.85rem}";class w extends p{constructor(){super(...arguments);n(this,"hasLoaded",!1);n(this,"loading",!1);n(this,"error",null);n(this,"data",null);n(this,"currentPage",1);n(this,"pageSize",10)}connectedCallback(){super.connectedCallback(),this.hasLoaded||(this.hasLoaded=!0,this.loadData())}async loadData(){this.loading=!0,this.error=null,this.render();try{const t=(this.currentPage-1)*this.pageSize,e=await fetch(`https://dummyjson.com/products?limit=${this.pageSize}&skip=${t}`);if(!e.ok)throw new Error(`Request failed: ${e.status}`);const a=await e.json(),s=[{key:"id",label:"ID",align:"right",visible:!1},{key:"title",label:"Title"},{key:"brand",label:"Brand"},{key:"category",label:"Category"},{key:"price",label:"Price",align:"right"},{key:"rating",label:"Rating",align:"right"},{key:"stock",label:"Stock",align:"right"},{key:"actions",label:"Actions",align:"center",actions:{edit:!0,delete:!0}}],o=a.products.map(i=>({id:i.id,title:i.title,brand:i.brand,category:i.category,price:`$${i.price.toFixed(2)}`,rating:i.rating.toFixed(1),stock:i.stock}));this.data={columns:s,rows:o,meta:{total:a.total,limit:a.limit,skip:a.skip}},this.loading=!1,this.render()}catch(t){this.loading=!1,this.error=t instanceof Error?t.message:"Unknown error",this.render()}}showActionMessage(t){const e=this.shadowRoot.querySelector("#action-message");e&&(e.textContent=t,e.style.display="block",setTimeout(()=>{const a=this.shadowRoot.querySelector("#action-message");a&&(a.style.display="none")},5e3))}render(){var h,u;this.shadowRoot.innerHTML=`
|
|
72
|
+
<style>${y}</style>
|
|
73
|
+
${v}
|
|
74
|
+
`;const t=this.shadowRoot.querySelector("#data-status"),e=this.shadowRoot.getElementById("confirmModal"),a=this.shadowRoot.getElementById("confirmDelete"),s=this.shadowRoot.getElementById("confirmCancel");s==null||s.addEventListener("click",()=>{e==null||e.close()}),t&&(t.textContent=this.loading?"Loading...":this.error?"Error":"Loaded",t.className=`status ${this.loading?"loading":this.error?"error":"success"}`);const o=this.shadowRoot.querySelector("#demo-table");o&&this.data&&(o.data={columns:this.data.columns,rows:this.data.rows});const i=this.shadowRoot.querySelector("ui-pagination");if(i&&((h=this.data)!=null&&h.meta)){i.total=this.data.meta.total,i.currentPage=this.currentPage,i.pageSize=this.pageSize;const d=i.cloneNode(!0);(u=i.parentNode)==null||u.replaceChild(d,i),d.addEventListener("page-change",l=>{this.currentPage=l.detail.page,this.loadData()})}const g=this.shadowRoot.querySelector("#demo-table");g&&(g.addEventListener("edit-action",d=>{const{row:l}=d.detail;this.showActionMessage(`EDIT clicked for "${l.id}: ${l.title}"`)}),g.addEventListener("delete-action",d=>{const{row:l}=d.detail;console.log(`DELETE clicked for "${l.id}: ${l.title}"`),e==null||e.open(),a==null||a.addEventListener("click",()=>{e==null||e.close(),this.showActionMessage(`DELETE confirmed for "${l.id}: ${l.title}"`)})}))}}customElements.define("table-demo",w);export{w as TableDemo};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
var u=Object.defineProperty;var h=(r,s,t)=>s in r?u(r,s,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[s]=t;var l=(r,s,t)=>h(r,typeof s!="symbol"?s+"":s,t);import{B as b,t as v}from"./index-BiVNQ5Fp.js";import"./vendor-BvJLUv9i.js";const g=':host{display:block}.tabs{background:var(--color-page-bg);border-radius:16px;box-shadow:0 1px 3px #0000000a,0 4px 12px #00000008;overflow:hidden;position:relative}.tablist{display:flex;position:relative;padding:8px;gap:4px;background:linear-gradient(180deg,#fafafa,#f5f5f5);border-bottom:1px solid rgba(0,0,0,.04)}.tab-indicator{position:absolute;bottom:8px;height:calc(100% - 16px);background:var(--color-page-bg);border-radius:10px;box-shadow:0 2px 8px #0000000f,0 1px 2px #0000000a;transition:transform .28s cubic-bezier(.4,0,.2,1),width .28s cubic-bezier(.4,0,.2,1);pointer-events:none;z-index:0}::slotted([slot="tab"]){-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:none;color:#64748b;cursor:pointer;font:600 13px/1 DM Sans,system-ui,-apple-system,sans-serif;letter-spacing:.02em;padding:10px 18px;position:relative;transition:color .2s ease;-webkit-user-select:none;user-select:none;white-space:nowrap;z-index:1}::slotted([slot="tab"]:hover){color:var(--color-ink)}::slotted([slot="tab"].is-active){color:var(--color-ink)}::slotted([slot="tab"]:focus-visible){outline:none}::slotted([slot="tab"]:focus-visible):after{content:"";position:absolute;top:6px;right:6px;bottom:6px;left:6px;border:2px solid var(--color-primary);border-radius:8px;pointer-events:none}.panels{padding:24px 28px;min-height:200px}::slotted([slot="panel"]){animation:fadeIn .3s ease}::slotted([slot="panel"]:not(.is-active)){display:none}@keyframes fadeIn{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion: reduce){.tab-indicator{transition:none}::slotted([slot="panel"]){animation:none}}';class m extends b{constructor(){super(...arguments);l(this,"activeId",null);l(this,"indicator",null);l(this,"handleTabClick",t=>{const a=t.target;if(!a)return;const i=a.closest('[slot="tab"][data-tab]');if(!i)return;t.preventDefault();const e=i.getAttribute("data-tab");e&&this.setActive(e)})}static get observedAttributes(){return["active"]}connectedCallback(){this.setAttribute("data-ui","tabs"),super.connectedCallback(),this.addEventListener("click",this.handleTabClick)}disconnectedCallback(){this.removeEventListener("click",this.handleTabClick),super.disconnectedCallback()}attributeChangedCallback(t,a,i){t==="active"&&a!==i&&(this.activeId=i,this.syncTabs())}setActive(t){this.activeId!==t&&(this.activeId=t,this.setAttribute("active",t),this.syncTabs(),this.dispatchEvent(new CustomEvent("tab-change",{bubbles:!0,composed:!0,detail:{id:t}})))}getTabs(){var a;const t=(a=this.shadowRoot)==null?void 0:a.querySelector('slot[name="tab"]');return t?t.assignedElements({flatten:!0}):[]}getPanels(){var a;const t=(a=this.shadowRoot)==null?void 0:a.querySelector('slot[name="panel"]');return t?t.assignedElements({flatten:!0}):[]}getActiveId(t){const a=this.getAttribute("active");if(a&&t.some(e=>e.getAttribute("data-tab")===a))return a;if(this.activeId&&t.some(e=>e.getAttribute("data-tab")===this.activeId))return this.activeId;const i=t.find(e=>e.getAttribute("data-tab"));return(i==null?void 0:i.getAttribute("data-tab"))??null}syncTabs(){const t=this.getTabs(),a=this.getPanels();if(t.length===0)return;const i=this.getActiveId(t);i&&(this.activeId=i,this.getAttribute("active")!==i&&this.setAttribute("active",i),t.forEach(e=>{const n=e.getAttribute("data-tab");if(!n)return;const d=e.id||`tab-${n}`,o=n===i;e.id=d,e.setAttribute("role","tab"),e.setAttribute("aria-selected",String(o)),e.setAttribute("tabindex",o?"0":"-1"),e.classList.toggle("is-active",o)}),a.forEach(e=>{const n=e.getAttribute("data-tab");if(!n)return;const d=e.id||`panel-${n}`,o=n===i;e.id=d,e.setAttribute("role","tabpanel"),e.toggleAttribute("hidden",!o),e.classList.toggle("is-active",o);const c=t.find(p=>p.getAttribute("data-tab")===n);c&&(c.setAttribute("aria-controls",d),e.setAttribute("aria-labelledby",c.id))}),this.updateIndicator(t,i))}updateIndicator(t,a){if(!this.indicator)return;const i=t.find(o=>o.getAttribute("data-tab")===a);if(!i)return;const e=this.shadowRoot.querySelector(".tablist");if(!e)return;i.getBoundingClientRect(),e.getBoundingClientRect();const n=t.indexOf(i);let d=0;for(let o=0;o<n;o++)d+=t[o].offsetWidth;this.indicator.style.transform=`translateX(${d}px)`,this.indicator.style.width=`${i.offsetWidth}px`}render(){this.shadowRoot.innerHTML=`
|
|
2
|
+
<style>${v}${g}</style>
|
|
3
|
+
<div class="tabs">
|
|
4
|
+
<div class="tablist" role="tablist">
|
|
5
|
+
<div class="tab-indicator"></div>
|
|
6
|
+
<slot name="tab"></slot>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="panels">
|
|
9
|
+
<slot name="panel"></slot>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
`,this.indicator=this.shadowRoot.querySelector(".tab-indicator");const t=this.shadowRoot.querySelector('slot[name="tab"]'),a=this.shadowRoot.querySelector('slot[name="panel"]');t==null||t.addEventListener("slotchange",()=>this.syncTabs()),a==null||a.addEventListener("slotchange",()=>this.syncTabs()),requestAnimationFrame(()=>this.syncTabs())}}customElements.define("ui-tabs",m);const f=`<h1>Tabs Demo</h1>\r
|
|
13
|
+
<p class="intro">A simple tabs component with slotted tabs and panels.</p>\r
|
|
14
|
+
\r
|
|
15
|
+
<div class="demo-section">\r
|
|
16
|
+
<h2>Basic Tabs</h2>\r
|
|
17
|
+
<ui-tabs id="basicTabs" active="overview">\r
|
|
18
|
+
<button slot="tab" data-tab="overview">Overview</button>\r
|
|
19
|
+
<button slot="tab" data-tab="usage">Usage</button>\r
|
|
20
|
+
<button slot="tab" data-tab="api">API</button>\r
|
|
21
|
+
\r
|
|
22
|
+
<div slot="panel" data-tab="overview">\r
|
|
23
|
+
<p>Use tabs to group related content without navigating away.</p>\r
|
|
24
|
+
<ul>\r
|
|
25
|
+
<li>Accessible roles and ARIA labels</li>\r
|
|
26
|
+
<li>Slotted tabs and panels</li>\r
|
|
27
|
+
<li>Simple active state</li>\r
|
|
28
|
+
</ul>\r
|
|
29
|
+
</div>\r
|
|
30
|
+
<div slot="panel" data-tab="usage">\r
|
|
31
|
+
<p>Set the active tab by using the <code>active</code> attribute.</p>\r
|
|
32
|
+
<pre><code><ui-tabs active="overview">...</ui-tabs></code></pre>\r
|
|
33
|
+
</div>\r
|
|
34
|
+
<div slot="panel" data-tab="api">\r
|
|
35
|
+
<p>Listen for <code>tab-change</code> events to react to changes.</p>\r
|
|
36
|
+
</div>\r
|
|
37
|
+
</ui-tabs>\r
|
|
38
|
+
</div>\r
|
|
39
|
+
\r
|
|
40
|
+
<div class="demo-section">\r
|
|
41
|
+
<h2>Product Tabs</h2>\r
|
|
42
|
+
<ui-tabs id="productTabs">\r
|
|
43
|
+
<button slot="tab" data-tab="details">Details</button>\r
|
|
44
|
+
<button slot="tab" data-tab="specs">Specs</button>\r
|
|
45
|
+
<button slot="tab" data-tab="shipping">Shipping</button>\r
|
|
46
|
+
\r
|
|
47
|
+
<div slot="panel" data-tab="details">\r
|
|
48
|
+
<p><strong>Storm Speaker</strong> is built for portable, punchy sound.</p>\r
|
|
49
|
+
</div>\r
|
|
50
|
+
<div slot="panel" data-tab="specs">\r
|
|
51
|
+
<ul>\r
|
|
52
|
+
<li>Battery: 18 hours</li>\r
|
|
53
|
+
<li>Water resistance: IPX5</li>\r
|
|
54
|
+
<li>Bluetooth: 5.3</li>\r
|
|
55
|
+
</ul>\r
|
|
56
|
+
</div>\r
|
|
57
|
+
<div slot="panel" data-tab="shipping">\r
|
|
58
|
+
<p>Ships in 1-2 business days. Free returns within 30 days.</p>\r
|
|
59
|
+
</div>\r
|
|
60
|
+
</ui-tabs>\r
|
|
61
|
+
<div class="result" id="tab-result" style="display: none;">\r
|
|
62
|
+
Active tab: <span id="tab-value"></span>\r
|
|
63
|
+
</div>\r
|
|
64
|
+
</div>\r
|
|
65
|
+
`,x=":host{display:block;padding:2rem;max-width:1100px;margin:0 auto}.intro{color:var(--color-ink, #0f172a);opacity:.8;margin-bottom:1.5rem}h1{font-size:2rem;margin-bottom:.5rem;color:var(--color-ink, #0f172a)}h2{font-size:1.4rem;margin-top:0;margin-bottom:.75rem;color:var(--color-ink, #0f172a)}.demo-section{margin-bottom:2rem;padding:1.5rem;border:1px solid #e2e8f0;border-radius:12px;background:#fff}.result{margin-top:1rem;padding:.75rem 1rem;border-radius:10px;background:#f1f5f9;color:#1e293b;font-weight:600}pre{background:#0f172a;color:#e2e8f0;padding:.75rem 1rem;border-radius:10px;overflow-x:auto}code{font-family:Courier New,monospace;font-size:.9rem}";class y extends b{render(){var t;this.shadowRoot.innerHTML=`
|
|
66
|
+
<style>${x}</style>
|
|
67
|
+
${f}
|
|
68
|
+
`;const s=this.shadowRoot.querySelector("#productTabs");if(s){const a=s.cloneNode(!0);(t=s.parentNode)==null||t.replaceChild(a,s),a.addEventListener("tab-change",i=>{const e=this.shadowRoot.getElementById("tab-result"),n=this.shadowRoot.getElementById("tab-value");e&&n&&(e.style.display="block",n.textContent=i.detail.id)})}}}customElements.define("tabs-demo",y);export{y as TabsDemo};
|
package/dist/index.html
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
|
-
|
|
2
1
|
<!DOCTYPE html>
|
|
3
2
|
<html lang="en">
|
|
4
3
|
<head>
|
|
5
4
|
<meta charset="UTF-8" />
|
|
6
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>Web Components
|
|
8
|
-
<
|
|
9
|
-
<link rel="
|
|
6
|
+
<title>Web Components UI Kit</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=Sora:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
10
|
+
<style>
|
|
11
|
+
* {
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding: 0;
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
html, body {
|
|
18
|
+
height: 100%;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
body {
|
|
22
|
+
font-family: "DM Sans", system-ui, -apple-system, sans-serif;
|
|
23
|
+
-webkit-font-smoothing: antialiased;
|
|
24
|
+
-moz-osx-font-smoothing: grayscale;
|
|
25
|
+
background: #f8f9fc;
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
28
|
+
<script type="module" crossorigin src="/webcomponents/assets/index-BiVNQ5Fp.js"></script>
|
|
29
|
+
<link rel="modulepreload" crossorigin href="/webcomponents/assets/vendor-BvJLUv9i.js">
|
|
30
|
+
<link rel="stylesheet" crossorigin href="/webcomponents/assets/index-DFxj0POj.css">
|
|
10
31
|
</head>
|
|
11
32
|
<body>
|
|
12
33
|
<div id="app"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diniz/webcomponents",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Lightweight web components library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/webcomponents.umd.js",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/feather-icons": "^4.29.4",
|
|
29
|
-
"@types/node": "^25.3.
|
|
30
|
-
"typescript": "^5.
|
|
31
|
-
"vite": "^5.
|
|
29
|
+
"@types/node": "^25.3.2",
|
|
30
|
+
"typescript": "^5.9.3",
|
|
31
|
+
"vite": "^5.4.21"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"feather-icons": "^4.29.2"
|