@designbasekorea/ui-wc 0.9.4 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/LICENSE-WORLD-MAP.md +10 -0
- package/README.md +60 -0
- package/dist/esm/components/db-accordion.d.ts +22 -10
- package/dist/esm/components/db-accordion.js +1 -1
- package/dist/esm/components/db-achievement-list.d.ts +2 -0
- package/dist/esm/components/db-achievement-list.js +1 -1
- package/dist/esm/components/db-activity-heatmap.d.ts +1 -0
- package/dist/esm/components/db-activity-heatmap.js +1 -1
- package/dist/esm/components/db-ad-banner.d.ts +2 -0
- package/dist/esm/components/db-ad-banner.js +1 -1
- package/dist/esm/components/db-ai-chat-list.d.ts +5 -1
- package/dist/esm/components/db-ai-chat-list.js +1 -1
- package/dist/esm/components/db-ai-chat.d.ts +2 -0
- package/dist/esm/components/db-ai-chat.js +1 -1
- package/dist/esm/components/db-ai-file-tree.js +1 -1
- package/dist/esm/components/db-alert.d.ts +1 -0
- package/dist/esm/components/db-alert.js +1 -1
- package/dist/esm/components/db-audio-player.d.ts +2 -0
- package/dist/esm/components/db-audio-player.js +1 -1
- package/dist/esm/components/db-avatar.d.ts +1 -0
- package/dist/esm/components/db-avatar.js +1 -1
- package/dist/esm/components/db-banner.d.ts +2 -0
- package/dist/esm/components/db-banner.js +1 -1
- package/dist/esm/components/db-button.d.ts +40 -2
- package/dist/esm/components/db-button.js +1 -1
- package/dist/esm/components/db-calendar.d.ts +5 -0
- package/dist/esm/components/db-calendar.js +1 -1
- package/dist/esm/components/db-card.d.ts +1 -0
- package/dist/esm/components/db-card.js +1 -1
- package/dist/esm/components/db-chat-composer.d.ts +3 -0
- package/dist/esm/components/db-chat-composer.js +1 -1
- package/dist/esm/components/db-chat-message.d.ts +2 -0
- package/dist/esm/components/db-chat-message.js +1 -1
- package/dist/esm/components/db-chat-orb.d.ts +13 -0
- package/dist/esm/components/db-chat-orb.js +1 -1
- package/dist/esm/components/db-chat-room.d.ts +1 -0
- package/dist/esm/components/db-chat-room.js +1 -1
- package/dist/esm/components/db-chat-typing.d.ts +2 -0
- package/dist/esm/components/db-chat-typing.js +1 -1
- package/dist/esm/components/db-chat-widget.d.ts +9 -0
- package/dist/esm/components/db-chat-widget.js +1 -1
- package/dist/esm/components/db-checkbox.d.ts +3 -0
- package/dist/esm/components/db-checkbox.js +1 -1
- package/dist/esm/components/db-chip.d.ts +2 -0
- package/dist/esm/components/db-chip.js +1 -1
- package/dist/esm/components/db-code-block.d.ts +1 -0
- package/dist/esm/components/db-code-block.js +1 -1
- package/dist/esm/components/db-color-picker.d.ts +4 -0
- package/dist/esm/components/db-color-picker.js +1 -1
- package/dist/esm/components/db-color-swatch.d.ts +3 -0
- package/dist/esm/components/db-color-swatch.js +1 -1
- package/dist/esm/components/db-confetti.d.ts +11 -5
- package/dist/esm/components/db-confetti.js +1 -1
- package/dist/esm/components/db-cookie-banner.d.ts +3 -0
- package/dist/esm/components/db-cookie-banner.js +1 -1
- package/dist/esm/components/db-countdown.d.ts +2 -1
- package/dist/esm/components/db-countdown.js +1 -1
- package/dist/esm/components/db-date-picker.d.ts +3 -0
- package/dist/esm/components/db-date-picker.js +1 -1
- package/dist/esm/components/db-dropdown.d.ts +1 -0
- package/dist/esm/components/db-dropdown.js +1 -1
- package/dist/esm/components/db-dropzone.d.ts +2 -0
- package/dist/esm/components/db-dropzone.js +1 -1
- package/dist/esm/components/db-email-verify.d.ts +37 -7
- package/dist/esm/components/db-email-verify.js +1 -1
- package/dist/esm/components/db-file-uploader.d.ts +2 -0
- package/dist/esm/components/db-file-uploader.js +1 -1
- package/dist/esm/components/db-floating-action-button.d.ts +1 -1
- package/dist/esm/components/db-floating-action-button.js +1 -1
- package/dist/esm/components/db-form.d.ts +2 -0
- package/dist/esm/components/db-form.js +1 -1
- package/dist/esm/components/db-gantt.d.ts +2 -0
- package/dist/esm/components/db-gantt.js +1 -1
- package/dist/esm/components/db-image-list.d.ts +3 -0
- package/dist/esm/components/db-image-list.js +1 -1
- package/dist/esm/components/db-image.d.ts +1 -0
- package/dist/esm/components/db-image.js +1 -1
- package/dist/esm/components/db-input-group.d.ts +30 -0
- package/dist/esm/components/db-input-group.js +1 -0
- package/dist/esm/components/db-input.d.ts +9 -1
- package/dist/esm/components/db-input.js +1 -1
- package/dist/esm/components/db-kanban.d.ts +3 -0
- package/dist/esm/components/db-kanban.js +1 -1
- package/dist/esm/components/db-lightbox.d.ts +2 -0
- package/dist/esm/components/db-lightbox.js +1 -1
- package/dist/esm/components/db-list.d.ts +2 -0
- package/dist/esm/components/db-list.js +1 -1
- package/dist/esm/components/db-markdown-editor.d.ts +2 -0
- package/dist/esm/components/db-markdown-editor.js +1 -1
- package/dist/esm/components/db-menu-item.js +1 -1
- package/dist/esm/components/db-navbar.d.ts +6 -0
- package/dist/esm/components/db-navbar.js +1 -1
- package/dist/esm/components/db-node.d.ts +1 -0
- package/dist/esm/components/db-node.js +1 -1
- package/dist/esm/components/db-onboarding-modal.d.ts +2 -0
- package/dist/esm/components/db-onboarding-modal.js +1 -1
- package/dist/esm/components/db-otp-input.d.ts +4 -1
- package/dist/esm/components/db-otp-input.js +1 -1
- package/dist/esm/components/db-page-header.d.ts +11 -0
- package/dist/esm/components/db-page-header.js +1 -1
- package/dist/esm/components/db-phone-verify.d.ts +33 -11
- package/dist/esm/components/db-phone-verify.js +1 -1
- package/dist/esm/components/db-popover.d.ts +1 -0
- package/dist/esm/components/db-popover.js +1 -1
- package/dist/esm/components/db-progress-step.d.ts +2 -0
- package/dist/esm/components/db-progress-step.js +1 -1
- package/dist/esm/components/db-radio.d.ts +3 -0
- package/dist/esm/components/db-radio.js +1 -1
- package/dist/esm/components/db-range-slider.d.ts +36 -7
- package/dist/esm/components/db-range-slider.js +1 -1
- package/dist/esm/components/db-rating.d.ts +1 -0
- package/dist/esm/components/db-rating.js +1 -1
- package/dist/esm/components/db-search-bar.d.ts +2 -0
- package/dist/esm/components/db-search-bar.js +1 -1
- package/dist/esm/components/db-section-logo-cloud.js +1 -1
- package/dist/esm/components/db-select.d.ts +35 -6
- package/dist/esm/components/db-select.js +1 -1
- package/dist/esm/components/db-share.d.ts +5 -0
- package/dist/esm/components/db-share.js +1 -1
- package/dist/esm/components/db-sidebar.d.ts +3 -0
- package/dist/esm/components/db-sidebar.js +1 -1
- package/dist/esm/components/db-signature.d.ts +2 -0
- package/dist/esm/components/db-signature.js +1 -1
- package/dist/esm/components/db-spinner.d.ts +2 -0
- package/dist/esm/components/db-spinner.js +1 -1
- package/dist/esm/components/db-stepper.d.ts +2 -0
- package/dist/esm/components/db-stepper.js +1 -1
- package/dist/esm/components/db-table.d.ts +2 -0
- package/dist/esm/components/db-table.js +1 -1
- package/dist/esm/components/db-tabs.d.ts +37 -13
- package/dist/esm/components/db-tabs.js +1 -1
- package/dist/esm/components/db-textarea.d.ts +13 -1
- package/dist/esm/components/db-textarea.js +1 -1
- package/dist/esm/components/db-ticket.js +1 -1
- package/dist/esm/components/db-time-picker.d.ts +2 -0
- package/dist/esm/components/db-time-picker.js +1 -1
- package/dist/esm/components/db-timeline.d.ts +4 -0
- package/dist/esm/components/db-timeline.js +1 -1
- package/dist/esm/components/db-toast.d.ts +2 -0
- package/dist/esm/components/db-toast.js +1 -1
- package/dist/esm/components/db-toggle.d.ts +33 -4
- package/dist/esm/components/db-toggle.js +1 -1
- package/dist/esm/components/db-tool-layout.d.ts +92 -0
- package/dist/esm/components/db-tool-layout.js +1 -0
- package/dist/esm/components/db-tool-panel.d.ts +50 -0
- package/dist/esm/components/db-tool-panel.js +1 -0
- package/dist/esm/components/db-top-banner.d.ts +2 -0
- package/dist/esm/components/db-top-banner.js +1 -1
- package/dist/esm/components/db-two-factor.d.ts +35 -12
- package/dist/esm/components/db-two-factor.js +1 -1
- package/dist/esm/components/db-video-player.d.ts +3 -0
- package/dist/esm/components/db-video-player.js +1 -1
- package/dist/esm/components/db-world-map.d.ts +60 -0
- package/dist/esm/components/db-world-map.js +1 -0
- package/dist/esm/components/db-youtube-player.d.ts +2 -0
- package/dist/esm/components/db-youtube-player.js +1 -1
- package/dist/esm/components/db-zoom-control.d.ts +52 -0
- package/dist/esm/components/db-zoom-control.js +1 -0
- package/dist/esm/components/input-validation.js +1 -1
- package/dist/esm/components/paper-card.d.ts +2 -0
- package/dist/esm/components/paper-card.js +1 -1
- package/dist/esm/core/control-label.js +1 -0
- package/dist/esm/core/i18n-copy.js +1 -1
- package/dist/esm/core/i18n-en.js +1 -1
- package/dist/esm/core/i18n.d.ts +31 -1
- package/dist/esm/core/i18n.js +1 -1
- package/dist/esm/core/range-values.js +1 -0
- package/dist/esm/core/text-field-state.js +1 -0
- package/dist/esm/helpers/world-countries.js +1 -0
- package/dist/esm/helpers/world-land.js +1 -0
- package/dist/esm/index.d.ts +6 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/node_modules/@designbasekorea/ui-contracts/dist/components.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +804 -83
- package/dist/index.esm.js +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.ts +6211 -648
- package/dist/react/index.esm.js +1 -1
- package/package.json +9 -4
|
@@ -4,31 +4,44 @@ import './db-otp-input.js';
|
|
|
4
4
|
import './db-select.js';
|
|
5
5
|
import { PHONE_VERIFY_SIZES } from '../ui-contracts/dist/components.d.js';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* ui-wc — db-phone-verify (수동 작성, 자동 동기화 대상 아님)
|
|
9
|
-
*
|
|
10
|
-
* 한국형 휴대폰 본인인증: 통신사 → 번호 → 인증번호 발송 → OTP + 타이머/재전송.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
7
|
type Size = (typeof PHONE_VERIFY_SIZES)[number];
|
|
8
|
+
type Step = 'phone' | 'code' | 'verified';
|
|
14
9
|
declare class DbPhoneVerify extends HTMLElement {
|
|
15
10
|
static get observedAttributes(): string[];
|
|
16
11
|
private built;
|
|
17
12
|
private timerId;
|
|
13
|
+
/** 인증번호 유효 시간(초) */
|
|
18
14
|
private remaining;
|
|
15
|
+
/** 재전송 버튼이 다시 열리기까지 남은 시간(초) */
|
|
16
|
+
private cooldownLeft;
|
|
17
|
+
private expired;
|
|
18
|
+
private closeBtn;
|
|
19
|
+
private headerEl;
|
|
20
|
+
private eyebrowEl;
|
|
21
|
+
private titleEl;
|
|
22
|
+
private descEl;
|
|
23
|
+
private formEl;
|
|
19
24
|
private carrierSelect;
|
|
20
25
|
private phoneInput;
|
|
21
26
|
private sendBtn;
|
|
27
|
+
private codeBlock;
|
|
28
|
+
private codeLabelEl;
|
|
22
29
|
private otpInput;
|
|
23
30
|
private timerEl;
|
|
24
|
-
private
|
|
31
|
+
private expiredEl;
|
|
25
32
|
private verifyBtn;
|
|
26
|
-
private
|
|
33
|
+
private resendHintEl;
|
|
34
|
+
private resendBtn;
|
|
35
|
+
private changeBtn;
|
|
36
|
+
private verifiedBlock;
|
|
37
|
+
private verifiedTitleEl;
|
|
38
|
+
private verifiedDescEl;
|
|
39
|
+
private doneBtn;
|
|
27
40
|
private errorEl;
|
|
28
41
|
get size(): Size;
|
|
29
42
|
set size(v: Size);
|
|
30
|
-
get step():
|
|
31
|
-
set step(v:
|
|
43
|
+
get step(): Step;
|
|
44
|
+
set step(v: Step);
|
|
32
45
|
get phone(): string;
|
|
33
46
|
set phone(v: string);
|
|
34
47
|
get carrier(): string;
|
|
@@ -37,6 +50,9 @@ declare class DbPhoneVerify extends HTMLElement {
|
|
|
37
50
|
set code(v: string);
|
|
38
51
|
get countdown(): number;
|
|
39
52
|
set countdown(v: number);
|
|
53
|
+
/** 재전송을 다시 누를 수 있기까지 기다리는 시간(초). 기본 30초. 0이면 바로 누를 수 있다. */
|
|
54
|
+
get resendCooldown(): number;
|
|
55
|
+
set resendCooldown(v: number);
|
|
40
56
|
connectedCallback(): void;
|
|
41
57
|
disconnectedCallback(): void;
|
|
42
58
|
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
@@ -46,13 +62,19 @@ declare class DbPhoneVerify extends HTMLElement {
|
|
|
46
62
|
restartCountdown(): void;
|
|
47
63
|
/** 인증 완료 상태로 전환합니다. */
|
|
48
64
|
markVerified(): void;
|
|
65
|
+
/** 번호 입력 단계로 돌아갑니다 (입력한 코드는 지웁니다). */
|
|
66
|
+
editPhone(): void;
|
|
49
67
|
private clearTimer;
|
|
50
|
-
private
|
|
68
|
+
private startTimers;
|
|
51
69
|
private renderTimer;
|
|
70
|
+
private emit;
|
|
52
71
|
private build;
|
|
53
72
|
private sync;
|
|
54
73
|
private isPhoneValid;
|
|
74
|
+
private requestSend;
|
|
55
75
|
private requestVerify;
|
|
76
|
+
/** 번역 문장 안의 {0} 자리에 값을 굵게 넣는다 — 언어마다 어순이 달라 조각내 번역하지 않는다. */
|
|
77
|
+
private setTextWithValue;
|
|
56
78
|
}
|
|
57
79
|
declare global {
|
|
58
80
|
interface HTMLElementTagNameMap {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dbFormat as t,dbText as e,t as i}from"../core/i18n.js";import"./db-button.js";import"./db-input.js";import"./db-otp-input.js";import"./db-select.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{PHONE_VERIFY_SIZES as r}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const DEFAULT_CARRIERS=()=>[{value:"skt",label:"SKT"},{value:"kt",label:"KT"},{value:"lgu",label:"LG U+"},{value:"mvno",label:e("알뜰폰")}];function el(t,e){const i=document.createElement(t);return e&&(i.className=e),i}function formatPhone(t){const e=t.replace(/\D/g,"").slice(0,11);return e.length<=3?e:e.length<=7?`${e.slice(0,3)}-${e.slice(3)}`:`${e.slice(0,3)}-${e.slice(3,7)}-${e.slice(7)}`}class DbPhoneVerify extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.timerId=null,this.remaining=0}static get observedAttributes(){return["carrier","phone","code","step","size","disabled","error","error-message","carrier-options","countdown","title","description","send-label","resend-label","verify-label","code-length","manual","sending","verifying","auto-submit"]}get size(){return s(this.getAttribute("size"),r,"m")}set size(t){this.setAttribute("size",t)}get step(){const t=this.getAttribute("step");return"code"===t||"verified"===t?t:"phone"}set step(t){this.setAttribute("step",t)}get phone(){return(this.getAttribute("phone")||"").replace(/\D/g,"")}set phone(t){this.setAttribute("phone",formatPhone(t))}get carrier(){return this.getAttribute("carrier")||"skt"}set carrier(t){this.setAttribute("carrier",t)}get code(){return this.getAttribute("code")||""}set code(t){this.setAttribute("code",t)}get countdown(){const t=Number(this.getAttribute("countdown")||180);return Number.isFinite(t)&&t>0?t:180}set countdown(t){this.setAttribute("countdown",String(t))}connectedCallback(){this.build(),this.sync(),"code"===this.step&&this.startTimer(this.countdown)}disconnectedCallback(){this.clearTimer()}attributeChangedCallback(t,e,i){this.built&&(this.sync(),"step"===t&&e!==i&&("code"===this.step?this.startTimer(this.countdown):this.clearTimer()))}startCodeStep(){"code"===this.step?this.startTimer(this.countdown):this.step="code",requestAnimationFrame(()=>this.otpInput?.focus?.())}restartCountdown(){"code"===this.step&&this.startTimer(this.countdown)}markVerified(){this.step="verified",this.clearTimer()}clearTimer(){this.timerId&&clearInterval(this.timerId),this.timerId=null,this.remaining=0}startTimer(t){this.clearTimer(),this.remaining=t,this.renderTimer(),this.timerId=setInterval(()=>{this.remaining-=1,this.renderTimer(),this.remaining<=0&&(this.clearTimer(),this.resendBtn.disabled=!1,this.dispatchEvent(new CustomEvent("db-countdown-complete",{bubbles:!0,composed:!0})))},1e3)}renderTimer(){const e=Math.max(0,Math.floor(this.remaining/60)),i=Math.max(0,this.remaining%60);this.timerEl.textContent=`${String(e).padStart(2,"0")}:${String(i).padStart(2,"0")}`,this.timerEl.setAttribute("aria-label",t("남은 시간 {0}분 {1}초",[e,i])),this.resendBtn.disabled=this.remaining>0||this.hasAttribute("disabled")}build(){if(this.built)return;this.built=!0;const t="designbase-wc-phone-verify";this.replaceChildren();const s=el("div",`${t}__header`),r=el("h3",`${t}__title`);r.dataset.role="title";const n=el("p",`${t}__description`);n.dataset.role="description",s.append(r,n);const o=el("div",`${t}__field`);this.carrierSelect=document.createElement("db-select"),this.carrierSelect.setAttribute("label","통신사"),this.carrierSelect.setAttribute("full-width",""),this.carrierSelect.setAttribute("placeholder",e("통신사 선택")),this.carrierSelect.addEventListener("db-change",t=>{t.stopPropagation();const e=t.detail?.value??this.carrierSelect.value;this.carrier=String(e||""),this.dispatchEvent(new CustomEvent("db-carrier-change",{detail:{carrier:this.carrier},bubbles:!0,composed:!0}))}),o.append(this.carrierSelect);const h=el("div",`${t}__phone-row`);this.phoneInput=document.createElement("db-input"),this.phoneInput.setAttribute("type","tel"),this.phoneInput.setAttribute("label","휴대폰 번호"),this.phoneInput.setAttribute("placeholder","010-0000-0000"),this.phoneInput.setAttribute("full-width",""),this.phoneInput.setAttribute("start-icon","user"),this.phoneInput.addEventListener("db-input",t=>{t.stopPropagation();const e=formatPhone(String(t.detail?.value??this.phoneInput.value??""));this.phoneInput.value=e,this.setAttribute("phone",e),this.dispatchEvent(new CustomEvent("db-phone-change",{detail:{phone:e.replace(/\D/g,""),formatted:e},bubbles:!0,composed:!0}))}),this.sendBtn=document.createElement("db-button"),this.sendBtn.setAttribute("variant","primary"),this.sendBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.isPhoneValid()&&(this.dispatchEvent(new CustomEvent("db-send-code",{detail:{carrier:this.carrier,phone:this.phone},bubbles:!0,composed:!0})),this.hasAttribute("manual")||this.startCodeStep())}),h.append(this.phoneInput,this.sendBtn),this.codeBlock=el("div",`${t}__code`);const a=el("div",`${t}__code-head`),d=el("span",`${t}__code-label`);d.textContent=e("인증번호"),this.timerEl=el("span",`${t}__timer`),a.append(d,this.timerEl),this.otpInput=document.createElement("db-otp-input"),this.otpInput.addEventListener("db-change",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.setAttribute("code",e),this.dispatchEvent(new CustomEvent("db-code-change",{detail:{code:e},bubbles:!0,composed:!0}))}),this.otpInput.addEventListener("db-complete",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.dispatchEvent(new CustomEvent("db-code-complete",{detail:{code:e,carrier:this.carrier,phone:this.phone},bubbles:!0,composed:!0})),this.hasAttribute("auto-submit")&&this.requestVerify()});const l=el("div",`${t}__code-actions`);this.resendBtn=el("button",`${t}__resend`),this.resendBtn.type="button",this.resendBtn.addEventListener("click",()=>{this.resendBtn.disabled||(this.dispatchEvent(new CustomEvent("db-resend",{detail:{carrier:this.carrier,phone:this.phone},bubbles:!0,composed:!0})),this.hasAttribute("manual")||this.startTimer(this.countdown))}),this.verifyBtn=document.createElement("db-button"),this.verifyBtn.setAttribute("variant","primary"),this.verifyBtn.setAttribute("full-width",""),this.verifyBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.requestVerify()}),l.append(this.resendBtn,this.verifyBtn),this.codeBlock.append(a,this.otpInput,l),this.errorEl=el("p",`${t}__error`),this.errorEl.hidden=!0;const c=el("div",`${t}__verified`);c.dataset.role="verified";const u=el("span",`${t}__verified-badge`);u.textContent=i("verify.done");const p=document.createElement("p");p.className=`${t}__verified-text`,p.textContent=i("verify.phoneDone"),c.append(u,p),this.append(s,o,h,this.codeBlock,this.errorEl,c)}sync(){const t="designbase-wc-phone-verify",e=this.size,i=this.step,s=this.hasAttribute("disabled"),r=function parseCarriers(t){if(!t)return DEFAULT_CARRIERS();try{const e=JSON.parse(t);return Array.isArray(e)&&e.length?e:DEFAULT_CARRIERS()}catch{return DEFAULT_CARRIERS()}}(this.getAttribute("carrier-options")),n=this.getAttribute("code-length")||"6";this.className=[t,`${t}--${e}`,`${t}--step-${i}`,s&&`${t}--disabled`,this.hasAttribute("error")&&`${t}--error`].filter(Boolean).join(" ");const o=this.querySelector('[data-role="title"]'),h=this.querySelector('[data-role="description"]');o.textContent=this.getAttribute("title")||"휴대폰 인증",h.textContent=this.getAttribute("description")||"본인 명의의 휴대폰 번호를 입력하고 인증번호를 받아 주세요.",this.carrierSelect.setAttribute("options",JSON.stringify(r)),this.carrierSelect.setAttribute("value",this.carrier),this.carrierSelect.setAttribute("size",e),this.carrierSelect.toggleAttribute("disabled",s||"verified"===i);const a=this.getAttribute("phone")||"";this.phoneInput.value=a,this.phoneInput.setAttribute("size",e),this.phoneInput.toggleAttribute("disabled",s||"phone"!==i),this.phoneInput.toggleAttribute("error",this.hasAttribute("error")&&"phone"===i),this.sendBtn.setAttribute("size",e),this.sendBtn.textContent=this.getAttribute("send-label")||"인증번호 받기",this.sendBtn.toggleAttribute("disabled",s||"phone"!==i||!this.isPhoneValid()),this.sendBtn.toggleAttribute("loading",this.hasAttribute("sending")),this.otpInput.setAttribute("length",n),this.otpInput.setAttribute("size",e),this.otpInput.setAttribute("value",this.getAttribute("code")||""),this.otpInput.toggleAttribute("disabled",s||"code"!==i),this.otpInput.toggleAttribute("error",this.hasAttribute("error")&&"code"===i),this.resendBtn.textContent=this.getAttribute("resend-label")||"재전송",this.verifyBtn.setAttribute("size",e),this.verifyBtn.textContent=this.getAttribute("verify-label")||"인증하기",this.verifyBtn.toggleAttribute("disabled",s||(this.getAttribute("code")||"").length<Number(n)),this.verifyBtn.toggleAttribute("loading",this.hasAttribute("verifying")),this.codeBlock.hidden="phone"===i;this.querySelector('[data-role="verified"]').hidden="verified"!==i;const d=this.getAttribute("error-message")||"";this.errorEl.textContent=d,this.errorEl.hidden=!this.hasAttribute("error")||!d}isPhoneValid(){return/^01[016789]\d{7,8}$/.test(this.phone)&&Boolean(this.carrier)}requestVerify(){const t=(this.code||this.otpInput.value).replace(/\D/g,""),e=Number(this.getAttribute("code-length")||6);"code"!==this.step||t.length!==e||this.hasAttribute("disabled")||this.dispatchEvent(new CustomEvent("db-verify",{detail:{carrier:this.carrier,phone:this.phone,code:t},bubbles:!0,composed:!0}))}}customElements.get("db-phone-verify")||customElements.define("db-phone-verify",DbPhoneVerify);export{DbPhoneVerify};
|
|
1
|
+
import{dbFormat as t,dbText as e}from"../core/i18n.js";import{createDbIcon as i}from"./db-icons.js";import"./db-button.js";import"./db-input.js";import"./db-otp-input.js";import"./db-select.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{PHONE_VERIFY_SIZES as r}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const DEFAULT_CARRIERS=()=>[{value:"skt",label:"SKT"},{value:"kt",label:"KT"},{value:"lgu",label:"LG U+"},{value:"mvno",label:e("알뜰폰")}];function el(t,e){const i=document.createElement(t);return e&&(i.className=e),i}function textButton(t,e){const i=el("button",t);return i.type="button",i.addEventListener("click",()=>{i.disabled||e()}),i}function formatPhone(t){const e=t.replace(/\D/g,"").slice(0,11);return e.length<=3?e:e.length<=7?`${e.slice(0,3)}-${e.slice(3)}`:`${e.slice(0,3)}-${e.slice(3,7)}-${e.slice(7)}`}class DbPhoneVerify extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.timerId=null,this.remaining=0,this.cooldownLeft=0,this.expired=!1}static get observedAttributes(){return["carrier","phone","code","step","size","disabled","error","error-message","carrier-options","countdown","resend-cooldown","eyebrow","title","description","send-label","resend-label","verify-label","done-label","code-length","closable","manual","sending","verifying","auto-submit"]}get size(){return s(this.getAttribute("size"),r,"m")}set size(t){this.setAttribute("size",t)}get step(){const t=this.getAttribute("step");return"code"===t||"verified"===t?t:"phone"}set step(t){this.setAttribute("step",t)}get phone(){return(this.getAttribute("phone")||"").replace(/\D/g,"")}set phone(t){this.setAttribute("phone",formatPhone(t))}get carrier(){return this.getAttribute("carrier")||"skt"}set carrier(t){this.setAttribute("carrier",t)}get code(){return this.getAttribute("code")||""}set code(t){this.setAttribute("code",t)}get countdown(){const t=Number(this.getAttribute("countdown")||180);return Number.isFinite(t)&&t>0?t:180}set countdown(t){this.setAttribute("countdown",String(t))}get resendCooldown(){const t=Number(this.getAttribute("resend-cooldown")??30);return Number.isFinite(t)&&t>=0?t:30}set resendCooldown(t){this.setAttribute("resend-cooldown",String(t))}connectedCallback(){this.build(),this.sync(),"code"===this.step&&this.startTimers()}disconnectedCallback(){this.clearTimer()}attributeChangedCallback(t,e,i){this.built&&("step"===t&&e!==i&&("code"===this.step?this.startTimers():this.clearTimer()),this.sync())}startCodeStep(){"code"===this.step?this.startTimers():this.step="code",requestAnimationFrame(()=>this.otpInput?.focus?.())}restartCountdown(){"code"===this.step&&this.startTimers()}markVerified(){this.step="verified"}editPhone(){this.removeAttribute("code"),this.step="phone",requestAnimationFrame(()=>this.phoneInput?.focus?.())}clearTimer(){this.timerId&&clearInterval(this.timerId),this.timerId=null,this.remaining=0,this.cooldownLeft=0,this.expired=!1}startTimers(){this.clearTimer(),this.remaining=this.countdown,this.cooldownLeft=Math.min(this.resendCooldown,this.countdown),this.renderTimer(),this.timerId=setInterval(()=>{this.cooldownLeft>0&&(this.cooldownLeft-=1),this.remaining>0&&(this.remaining-=1,this.remaining<=0&&(this.expired=!0,this.cooldownLeft=0,this.emit("db-countdown-complete"))),this.renderTimer(),this.remaining<=0&&this.cooldownLeft<=0&&this.timerId&&(clearInterval(this.timerId),this.timerId=null)},1e3)}renderTimer(){if(!this.built)return;const i=Math.max(0,Math.floor(this.remaining/60)),s=Math.max(0,this.remaining%60);this.timerEl.textContent=`${String(i).padStart(2,"0")}:${String(s).padStart(2,"0")}`,this.timerEl.setAttribute("aria-label",t("남은 시간 {0}분 {1}초",[i,s])),this.timerEl.classList.toggle("designbase-wc-phone-verify__timer--expired",this.expired),this.expiredEl.hidden=!this.expired,this.otpInput.toggleAttribute("disabled",this.hasAttribute("disabled")||"code"!==this.step||this.expired);const r=this.cooldownLeft>0;this.resendBtn.textContent=r?t("재전송 ({0}초)",[this.cooldownLeft]):this.getAttribute("resend-label")||e("재전송"),this.resendBtn.disabled=r||this.hasAttribute("disabled");const n=Number(this.getAttribute("code-length")||6);this.verifyBtn.toggleAttribute("disabled",this.hasAttribute("disabled")||"code"!==this.step||this.expired||this.code.length!==n)}emit(t,e={}){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}build(){if(this.built)return;this.built=!0;const t="designbase-wc-phone-verify";this.replaceChildren();const s=el("div",`${t}__shell`);this.closeBtn=el("button",`${t}__close`),this.closeBtn.type="button",this.closeBtn.setAttribute("aria-label",e("닫기")),this.closeBtn.append(i("close",18)),this.closeBtn.addEventListener("click",()=>this.emit("db-close")),this.headerEl=el("div",`${t}__header`),this.eyebrowEl=el("span",`${t}__eyebrow`),this.titleEl=el("h3",`${t}__title`),this.descEl=el("p",`${t}__description`),this.headerEl.append(this.eyebrowEl,this.titleEl,this.descEl),this.formEl=el("div",`${t}__form`),this.carrierSelect=document.createElement("db-select"),this.carrierSelect.setAttribute("full-width",""),this.carrierSelect.addEventListener("db-change",t=>{t.stopPropagation();const e=t.detail?.value??this.carrierSelect.value;this.carrier=String(e||""),this.emit("db-carrier-change",{carrier:this.carrier})});const r=el("div",`${t}__phone-row`);this.phoneInput=document.createElement("db-input"),this.phoneInput.setAttribute("type","tel"),this.phoneInput.setAttribute("inputmode","numeric"),this.phoneInput.setAttribute("autocomplete","tel-national"),this.phoneInput.setAttribute("placeholder","010-0000-0000"),this.phoneInput.setAttribute("full-width",""),this.phoneInput.setAttribute("start-icon","mobile"),this.phoneInput.addEventListener("db-input",t=>{t.stopPropagation();const e=formatPhone(String(t.detail?.value??this.phoneInput.value??""));this.phoneInput.value=e,this.setAttribute("phone",e),this.emit("db-phone-change",{phone:e.replace(/\D/g,""),formatted:e})}),this.phoneInput.addEventListener("keydown",t=>{"Enter"===t.key&&this.requestSend()}),this.sendBtn=document.createElement("db-button"),this.sendBtn.setAttribute("variant","primary"),this.sendBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.requestSend()}),r.append(this.phoneInput,this.sendBtn),this.formEl.append(this.carrierSelect,r),this.codeBlock=el("div",`${t}__code`);const n=el("div",`${t}__code-head`);this.codeLabelEl=el("span",`${t}__code-label`),this.timerEl=el("span",`${t}__timer`),this.timerEl.setAttribute("role","timer"),n.append(this.codeLabelEl,this.timerEl),this.otpInput=document.createElement("db-otp-input"),this.otpInput.setAttribute("full-width",""),this.otpInput.addEventListener("db-change",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.setAttribute("code",e),this.emit("db-code-change",{code:e})}),this.otpInput.addEventListener("db-complete",t=>{t.stopPropagation();const e=String(t.detail?.value||"");this.emit("db-code-complete",{code:e,carrier:this.carrier,phone:this.phone}),this.hasAttribute("auto-submit")&&this.requestVerify()}),this.expiredEl=el("p",`${t}__expired`),this.expiredEl.setAttribute("role","alert"),this.expiredEl.hidden=!0,this.verifyBtn=document.createElement("db-button"),this.verifyBtn.setAttribute("variant","primary"),this.verifyBtn.setAttribute("full-width",""),this.verifyBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.requestVerify()}),this.resendBtn=textButton(`${t}__link`,()=>{this.emit("db-resend",{carrier:this.carrier,phone:this.phone}),this.hasAttribute("manual")||(this.removeAttribute("code"),this.startTimers())}),this.changeBtn=textButton(`${t}__link ${t}__link--muted`,()=>{this.emit("db-change-phone",{carrier:this.carrier,phone:this.phone}),this.hasAttribute("manual")||this.editPhone()});const h=el("div",`${t}__footer`),o=el("span",`${t}__footer-resend`);this.resendHintEl=el("span",`${t}__footer-hint`),o.append(this.resendHintEl,this.resendBtn),h.append(o,this.changeBtn),this.codeBlock.append(n,this.otpInput,this.expiredEl,this.verifyBtn,h),this.verifiedBlock=el("div",`${t}__result ${t}__result--success`);const d=el("div",`${t}__result-icon`);d.append(i("circle-checked",36)),this.verifiedTitleEl=el("h3",`${t}__result-title`),this.verifiedDescEl=el("p",`${t}__result-desc`),this.doneBtn=document.createElement("db-button"),this.doneBtn.setAttribute("variant","primary"),this.doneBtn.setAttribute("full-width",""),this.doneBtn.addEventListener("db-click",t=>{t.stopPropagation(),this.emit("db-done",{carrier:this.carrier,phone:this.phone})}),this.verifiedBlock.append(d,this.verifiedTitleEl,this.verifiedDescEl,this.doneBtn),this.errorEl=el("p",`${t}__error`),this.errorEl.setAttribute("role","alert"),this.errorEl.hidden=!0,s.append(this.closeBtn,this.headerEl,this.formEl,this.errorEl,this.codeBlock,this.verifiedBlock),this.append(s)}sync(){const t="designbase-wc-phone-verify",i=this.size,s=this.step,r=this.hasAttribute("disabled"),n=function parseCarriers(t){if(!t)return DEFAULT_CARRIERS();try{const e=JSON.parse(t);return Array.isArray(e)&&e.length?e:DEFAULT_CARRIERS()}catch{return DEFAULT_CARRIERS()}}(this.getAttribute("carrier-options")),h=this.getAttribute("code-length")||"6",o=formatPhone(this.getAttribute("phone")||"")||"010-0000-0000";this.className=[t,`${t}--${i}`,`${t}--step-${s}`,this.hasAttribute("closable")&&`${t}--closable`,r&&`${t}--disabled`,this.hasAttribute("error")&&`${t}--error`].filter(Boolean).join(" "),this.closeBtn.hidden=!this.hasAttribute("closable"),this.headerEl.hidden="verified"===s;const d=this.getAttribute("eyebrow")||"";this.eyebrowEl.textContent=d,this.eyebrowEl.hidden=!d,"code"===s?(this.titleEl.textContent=e("인증번호를 입력해 주세요"),this.setTextWithValue(this.descEl,"{0} 번호로 {1}자리 인증번호를 보냈어요.",o,[h])):(this.titleEl.textContent=this.getAttribute("title")||e("휴대폰 인증"),this.descEl.textContent=this.getAttribute("description")||e("본인 명의의 휴대폰 번호를 입력해 주세요. 입력한 번호로 인증번호를 보내 드려요.")),this.formEl.hidden="phone"!==s,this.carrierSelect.setAttribute("label",e("통신사")),this.carrierSelect.setAttribute("placeholder",e("통신사 선택")),this.carrierSelect.setAttribute("options",JSON.stringify(n)),this.carrierSelect.setAttribute("value",this.carrier),this.carrierSelect.setAttribute("size",i),this.carrierSelect.toggleAttribute("disabled",r),this.phoneInput.setAttribute("label",e("휴대폰 번호")),this.phoneInput.value=this.getAttribute("phone")||"",this.phoneInput.setAttribute("size",i),this.phoneInput.toggleAttribute("disabled",r),this.phoneInput.toggleAttribute("error",this.hasAttribute("error")&&"phone"===s),this.sendBtn.setAttribute("size",i),this.sendBtn.textContent=this.getAttribute("send-label")||e("인증번호 받기"),this.sendBtn.toggleAttribute("disabled",r||!this.isPhoneValid()),this.sendBtn.toggleAttribute("loading",this.hasAttribute("sending")),this.codeBlock.hidden="code"!==s,this.codeLabelEl.textContent=e("인증번호"),this.otpInput.setAttribute("length",h),this.otpInput.setAttribute("size",i),this.otpInput.setAttribute("value",this.code),this.otpInput.toggleAttribute("error",this.hasAttribute("error")&&"code"===s),this.expiredEl.textContent=e("인증 시간이 만료되었어요. 인증번호를 다시 받아 주세요."),this.verifyBtn.setAttribute("size",i),this.verifyBtn.textContent=this.getAttribute("verify-label")||e("인증하기"),this.verifyBtn.toggleAttribute("loading",this.hasAttribute("verifying")),this.resendHintEl.textContent=e("문자를 받지 못하셨나요?"),this.changeBtn.textContent=e("번호 변경"),this.changeBtn.disabled=r,this.verifiedBlock.hidden="verified"!==s,this.verifiedTitleEl.textContent=e("휴대폰 인증 완료"),this.setTextWithValue(this.verifiedDescEl,"{0} 번호가 인증되었어요.",o),this.doneBtn.setAttribute("size",i),this.doneBtn.textContent=this.getAttribute("done-label")||e("확인");const l=this.getAttribute("error-message")||"";this.errorEl.textContent=l,this.errorEl.hidden=!this.hasAttribute("error")||!l||"verified"===s;const a="code"===s?this.otpInput:this.formEl;this.errorEl.previousElementSibling!==a&&a.after(this.errorEl),this.renderTimer()}isPhoneValid(){return/^01[016789]\d{7,8}$/.test(this.phone)&&Boolean(this.carrier)}requestSend(){"phone"===this.step&&(this.hasAttribute("disabled")||this.hasAttribute("sending")||!this.isPhoneValid()||(this.emit("db-send-code",{carrier:this.carrier,phone:this.phone}),this.hasAttribute("manual")||this.startCodeStep()))}requestVerify(){const t=(this.code||this.otpInput.value).replace(/\D/g,""),e=Number(this.getAttribute("code-length")||6);"code"!==this.step||this.expired||t.length!==e||this.hasAttribute("disabled")||this.emit("db-verify",{carrier:this.carrier,phone:this.phone,code:t})}setTextWithValue(t,i,s,r=[]){const n=e(i).replace(/\{(\d+)\}/g,(t,e)=>"0"===e?t:String(r[Number(e)-1]??"")),[h,o=""]=n.split("{0}"),d=document.createElement("strong");d.textContent=s,t.replaceChildren(document.createTextNode(h),d,document.createTextNode(o))}}customElements.get("db-phone-verify")||customElements.define("db-phone-verify",DbPhoneVerify);export{DbPhoneVerify};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{inheritThemeScope as e}from"../core/theme-scope.js";import{dbText as t}from"../core/i18n.js";import{POPOVER_PLACEMENTS as i,POPOVER_TRIGGERS as s}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbPopover extends HTMLElement{constructor(){super(...arguments),this.onDocMouseDown=null,this.onDocKeyDown=null,this.onExternalTriggerClick=null,this.handleTriggerClick=e=>{"click"===this.resolvedTrigger()&&(e.preventDefault(),e.stopPropagation(),this.setOpen(!this.isOpen()))},this.handleTriggerMouseEnter=()=>{"hover"===this.resolvedTrigger()&&this.scheduleOpen()},this.handleTriggerMouseLeave=()=>{"hover"===this.resolvedTrigger()&&this.scheduleClose()},this.handleTriggerFocus=()=>{"focus"===this.resolvedTrigger()&&this.scheduleOpen()},this.handleTriggerBlur=()=>{"focus"===this.resolvedTrigger()&&this.scheduleClose()},this.handleReposition=()=>{this.isOpen()&&(this.repositionRaf&&cancelAnimationFrame(this.repositionRaf),this.repositionRaf=requestAnimationFrame(()=>{this.positionPanel(),this.repositionRaf=void 0}))}}static get observedAttributes(){return["open","placement","position","title","content","size","variant","trigger","delay","hide-delay","always-show","disabled","max-width","show-arrow","close-on-outside-click","close-on-escape","trigger-id"]}get open(){return this.hasAttribute("open")&&"false"!==this.getAttribute("open")}set open(e){e?this.setAttribute("open",""):this.removeAttribute("open")}connectedCallback(){this.classList.add("designbase-wc-popover-host"),this.hasAttribute("placement")||this.hasAttribute("position")||this.setAttribute("placement","top"),this.render(),this.childObserver=new MutationObserver(()=>this.render()),this.childObserver.observe(this,{childList:!0}),this.bindExternalTrigger(),this.attachGlobalListeners(),this.syncOpenFromAttributes()}disconnectedCallback(){this.childObserver?.disconnect(),this.clearTimers(),this.repositionRaf&&cancelAnimationFrame(this.repositionRaf),this.unbindExternalTrigger(),this.detachGlobalListeners(),this.removePanel()}attributeChangedCallback(e){this.isConnected&&("trigger-id"===e&&(this.unbindExternalTrigger(),this.bindExternalTrigger()),"open"!==e&&"always-show"!==e&&"disabled"!==e?("content"===e&&this.bodyEl&&(this.bodyEl.textContent=this.getAttribute("content")||""),this.isOpen()&&(this.updatePanelMetadata(),requestAnimationFrame(()=>this.positionPanel()))):this.syncOpenFromAttributes())}resolvedPlacement(){const e=this.getAttribute("position")||this.getAttribute("placement")||"top";return i.includes(e)?e:"top"}resolvedTrigger(){const e=this.getAttribute("trigger")||"click";return s.includes(e)?e:"click"}isControlled(){return this.hasAttribute("open")}isOpen(){return!this.hasAttribute("disabled")&&(!!this.hasAttribute("always-show")||(this.isControlled()?"false"!==this.getAttribute("open"):this.panel?.classList.contains("designbase-wc-popover--visible")??!1))}setOpen(e){this.hasAttribute("disabled")||this.hasAttribute("always-show")||(this.isControlled()?e?this.setAttribute("open",""):this.removeAttribute("open"):e?this.showPanel():this.hidePanel(),this.dispatchEvent(new CustomEvent("db-open-change",{bubbles:!0,composed:!0,detail:{open:e}})),e||this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0})))}syncOpenFromAttributes(){this.hasAttribute("always-show")?this.showPanel():this.isControlled()&&("false"!==this.getAttribute("open")?this.showPanel():this.hidePanel())}clearTimers(){this.showTimer&&clearTimeout(this.showTimer),this.hideTimer&&clearTimeout(this.hideTimer),this.showTimer=void 0,this.hideTimer=void 0}groupOf(e){return e.startsWith("top")?"top":e.startsWith("bottom")?"bottom":e.startsWith("left")?"left":"right"}collectTriggerChildren(){const isInternalNode=e=>e.hasAttribute("data-wc-internal")||"content"===e.getAttribute("slot")||e===this.triggerWrap,e=Array.from(this.children).filter(e=>!isInternalNode(e));return e.length>0?e:Array.from(this.triggerWrap?.children||[]).filter(e=>"content"!==e.getAttribute("slot"))}ensureTriggerWrap(){this.triggerWrap||(this.triggerWrap=document.createElement("span"),this.triggerWrap.className="designbase-wc-popover__trigger",this.triggerWrap.setAttribute("data-wc-internal",""),this.triggerWrap.tabIndex=this.hasAttribute("trigger-id")?-1:0,this.triggerWrap.addEventListener("click",this.handleTriggerClick),this.triggerWrap.addEventListener("mouseenter",this.handleTriggerMouseEnter),this.triggerWrap.addEventListener("mouseleave",this.handleTriggerMouseLeave),this.triggerWrap.addEventListener("focus",this.handleTriggerFocus),this.triggerWrap.addEventListener("blur",this.handleTriggerBlur))}mountTriggerChildren(e){this.triggerWrap&&e.forEach(e=>{e.parentElement!==this.triggerWrap&&this.triggerWrap.append(e)})}collectBodyChildren(){return[...Array.from(this.querySelectorAll(':scope > [slot="content"]')),...Array.from(this.bodyEl?.querySelectorAll(':scope > [slot="content"]')||[])]}bindExternalTrigger(){const e=this.getAttribute("trigger-id");e&&(this.triggerEl=document.getElementById(e),this.triggerEl&&(this.onExternalTriggerClick=()=>{"click"===this.resolvedTrigger()&&this.setOpen(!this.isOpen())},this.triggerEl.addEventListener("click",this.onExternalTriggerClick)))}unbindExternalTrigger(){this.triggerEl&&this.onExternalTriggerClick&&this.triggerEl.removeEventListener("click",this.onExternalTriggerClick),this.triggerEl=null,this.onExternalTriggerClick=null}attachGlobalListeners(){this.onDocMouseDown=e=>{if(!this.isOpen()||"false"===this.getAttribute("close-on-outside-click"))return;const t=e.target;this.panel?.contains(t)||this.triggerWrap?.contains(t)||this.triggerEl?.contains(t)||this.setOpen(!1)},this.onDocKeyDown=e=>{"Escape"===e.key&&this.isOpen()&&"false"!==this.getAttribute("close-on-escape")&&this.setOpen(!1)},document.addEventListener("mousedown",this.onDocMouseDown),document.addEventListener("keydown",this.onDocKeyDown)}detachGlobalListeners(){this.onDocMouseDown&&document.removeEventListener("mousedown",this.onDocMouseDown),this.onDocKeyDown&&document.removeEventListener("keydown",this.onDocKeyDown),this.onDocMouseDown=null,this.onDocKeyDown=null}scheduleOpen(){this.clearTimers();const e="hover"===this.resolvedTrigger()?Math.max(0,Number(this.getAttribute("delay")||0)):0;this.showTimer=setTimeout(()=>this.showPanel(),e)}scheduleClose(){this.clearTimers();const e="hover"===this.resolvedTrigger()?Math.max(0,Number(this.getAttribute("hide-delay")||80)):0;this.hideTimer=setTimeout(()=>this.setOpen(!1),e)}getTriggerRect(){const e=this.triggerEl||this.triggerWrap;return e?.getBoundingClientRect()}flipPlacementIfNeeded(e,t,i){const s=window.innerHeight,r=window.innerWidth,o=this.groupOf(e),n=t.top-i.height-8>=8,a=t.bottom+8+i.height<=s-8,h=t.left-i.width-8>=8,l=t.right+8+i.width<=r-8;return"top"===o&&!n&&a?e.replace(/^top/,"bottom"):"bottom"===o&&!a&&n?e.replace(/^bottom/,"top"):"left"===o&&!h&&l?e.replace(/^left/,"right"):"right"===o&&!l&&h?e.replace(/^right/,"left"):e}applyCoords(e,t,i){let s=0,r=0,o=0,n=0;const a=i.height,h=i.width,l=16;switch(e){case"top":s=t.top-i.height-8,r=t.left+t.width/2-i.width/2,o=a-5,n=h/2-5;break;case"top-start":s=t.top-i.height-8,r=t.left,o=a-5,n=11;break;case"top-end":s=t.top-i.height-8,r=t.right-i.width,o=a-5,n=h-l-5;break;case"bottom":s=t.bottom+8,r=t.left+t.width/2-i.width/2,o=-5,n=h/2-5;break;case"bottom-start":s=t.bottom+8,r=t.left,o=-5,n=11;break;case"bottom-end":s=t.bottom+8,r=t.right-i.width,o=-5,n=h-l-5;break;case"left":s=t.top+t.height/2-i.height/2,r=t.left-i.width-8,o=a/2-5,n=h-5;break;case"left-start":s=t.top,r=t.left-i.width-8,o=11,n=h-5;break;case"left-end":s=t.bottom-i.height,r=t.left-i.width-8,o=a-l-5,n=h-5;break;case"right":s=t.top+t.height/2-i.height/2,r=t.right+8,o=a/2-5,n=-5;break;case"right-start":s=t.top,r=t.right+8,o=11,n=-5;break;case"right-end":s=t.bottom-i.height,r=t.right+8,o=a-l-5,n=-5}const d=window.innerWidth,c=window.innerHeight;return r<8&&(r=8),r+i.width>d-8&&(r=d-i.width-8),s<8&&(s=8),s+i.height>c-8&&(s=c-i.height-8),{top:s,left:r,aTop:o,aLeft:n,placement:e}}positionPanel(){if(!this.panel)return;const e=this.getTriggerRect();if(!e)return;const t=Number(this.getAttribute("max-width")||300);this.panel.style.maxWidth=`${t}px`,this.panel.offsetHeight;const s=this.panel.getBoundingClientRect(),r=this.resolvedPlacement(),o=this.flipPlacementIfNeeded(r,e,s),{top:n,left:a,aTop:h,aLeft:l}=this.applyCoords(o,e,s);this.panel.style.top=`${n}px`,this.panel.style.left=`${a}px`,this.panel.dataset.placementGroup=this.groupOf(o),i.forEach(e=>{this.panel.classList.toggle(`designbase-wc-popover--${e}`,e===o)}),this.arrowEl&&(this.arrowEl.className=`designbase-wc-popover__arrow designbase-wc-popover__arrow--${o}`,this.arrowEl.style.top=`${h}px`,this.arrowEl.style.left=`${l}px`)}revealPanel(){this.panel&&(this.panel.classList.remove("designbase-wc-popover--visible"),this.positionPanel(),this.panel.offsetHeight,this.positionPanel(),this.panel.classList.add("designbase-wc-popover--visible"))}updatePanelMetadata(){if(!this.panel)return;const e=this.getAttribute("size")||"m",t=this.getAttribute("variant")||"default",i=this.resolvedPlacement();this.panel.className=["designbase-wc-popover",`designbase-wc-popover--${e}`,`designbase-wc-popover--${t}`,`designbase-wc-popover--${i}`,this.isOpen()?"designbase-wc-popover--visible":"",this.hasAttribute("disabled")?"designbase-wc-popover--disabled":""].filter(Boolean).join(" ")}ensurePanel(){if(this.panel)return;const i=document.createElement("div");i.className="designbase-wc-popover",i.setAttribute("data-wc-internal",""),i.setAttribute("role","dialog"),i.setAttribute("aria-modal","false"),i.style.position="fixed",i.style.zIndex="9999";const s=document.createElement("div");s.className="designbase-wc-popover__content";const r=document.createElement("div");r.className="designbase-wc-popover__header";const o=document.createElement("h3");o.className="designbase-wc-popover__title";const n=document.createElement("db-button");n.className="designbase-wc-popover__close-button",n.setAttribute("variant","ghost"),n.setAttribute("size","s"),n.setAttribute("icon-only",""),n.setAttribute("start-icon","close"),n.setAttribute("aria-label",t("팝오버 닫기")),n.addEventListener("db-click",e=>{e.stopPropagation(),this.setOpen(!1)}),r.append(o,n),this.bodyEl=document.createElement("div"),this.bodyEl.className="designbase-wc-popover__body",s.append(r,this.bodyEl),i.append(s),"false"!==this.getAttribute("show-arrow")&&(this.arrowEl=document.createElement("div"),this.arrowEl.className=`designbase-wc-popover__arrow designbase-wc-popover__arrow--${this.resolvedPlacement()}`,i.append(this.arrowEl)),this.panel=i,this.panel.querySelector(".designbase-wc-popover__title").textContent=this.getAttribute("title")||"",this.panel.querySelector(".designbase-wc-popover__title").hidden=!this.getAttribute("title"),e(this,i),document.body.append(i),i.addEventListener("mouseenter",()=>{"hover"===this.resolvedTrigger()&&this.clearTimers()}),i.addEventListener("mouseleave",()=>{"hover"===this.resolvedTrigger()&&this.scheduleClose()})}showPanel(){if(this.hasAttribute("disabled"))return;this.ensurePanel(),this.updatePanelMetadata();const e=this.collectBodyChildren();e.length>0?this.bodyEl.replaceChildren(...e):this.bodyEl.textContent=this.getAttribute("content")||"";const t=this.panel.querySelector(".designbase-wc-popover__title");t.textContent=this.getAttribute("title")||"",t.hidden=!this.getAttribute("title"),requestAnimationFrame(()=>{this.revealPanel(),window.addEventListener("scroll",this.handleReposition,{capture:!0,passive:!0}),window.addEventListener("resize",this.handleReposition)})}hidePanel(){this.panel?.classList.remove("designbase-wc-popover--visible"),window.removeEventListener("scroll",this.handleReposition,!0),window.removeEventListener("resize",this.handleReposition),this.hasAttribute("always-show")||this.removePanel()}removePanel(){this.bodyEl?.querySelectorAll(':scope > [slot="content"]').forEach(e=>this.append(e)),this.panel?.remove(),this.panel=void 0,this.bodyEl=void 0,this.arrowEl=void 0}render(){this.ensureTriggerWrap();const e=this.collectTriggerChildren();this.mountTriggerChildren(e);const t=Boolean(this.getAttribute("trigger-id"));this.triggerWrap&&(e.length>0||!t?this.triggerWrap.parentElement!==this&&this.append(this.triggerWrap):this.triggerWrap.parentElement===this&&this.triggerWrap.remove()),this.hasAttribute("always-show")&&this.showPanel()}}customElements.get("db-popover")||customElements.define("db-popover",DbPopover);export{DbPopover};
|
|
1
|
+
import{inheritThemeScope as e}from"../core/theme-scope.js";import{subscribeDbLocale as t,dbText as i}from"../core/i18n.js";import{POPOVER_PLACEMENTS as s,POPOVER_TRIGGERS as r}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbPopover extends HTMLElement{constructor(){super(...arguments),this.onDocMouseDown=null,this.onDocKeyDown=null,this.onExternalTriggerClick=null,this.handleTriggerClick=e=>{"click"===this.resolvedTrigger()&&(e.preventDefault(),e.stopPropagation(),this.setOpen(!this.isOpen()))},this.handleTriggerMouseEnter=()=>{"hover"===this.resolvedTrigger()&&this.scheduleOpen()},this.handleTriggerMouseLeave=()=>{"hover"===this.resolvedTrigger()&&this.scheduleClose()},this.handleTriggerFocus=()=>{"focus"===this.resolvedTrigger()&&this.scheduleOpen()},this.handleTriggerBlur=()=>{"focus"===this.resolvedTrigger()&&this.scheduleClose()},this.handleReposition=()=>{this.isOpen()&&(this.repositionRaf&&cancelAnimationFrame(this.repositionRaf),this.repositionRaf=requestAnimationFrame(()=>{this.positionPanel(),this.repositionRaf=void 0}))}}static get observedAttributes(){return["open","placement","position","title","content","size","variant","trigger","delay","hide-delay","always-show","disabled","max-width","show-arrow","close-on-outside-click","close-on-escape","trigger-id"]}get open(){return this.hasAttribute("open")&&"false"!==this.getAttribute("open")}set open(e){e?this.setAttribute("open",""):this.removeAttribute("open")}connectedCallback(){this.classList.add("designbase-wc-popover-host"),this.hasAttribute("placement")||this.hasAttribute("position")||this.setAttribute("placement","top"),this.render(),this.childObserver=new MutationObserver(()=>this.render()),this.childObserver.observe(this,{childList:!0}),this.bindExternalTrigger(),this.attachGlobalListeners(),this.syncOpenFromAttributes(),this.unsubscribeLocale?.(),this.unsubscribeLocale=t(()=>this.panel?.querySelector(".designbase-wc-popover__close-button")?.setAttribute("aria-label",i("팝오버 닫기")))}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.childObserver?.disconnect(),this.clearTimers(),this.repositionRaf&&cancelAnimationFrame(this.repositionRaf),this.unbindExternalTrigger(),this.detachGlobalListeners(),this.removePanel()}attributeChangedCallback(e){this.isConnected&&("trigger-id"===e&&(this.unbindExternalTrigger(),this.bindExternalTrigger()),"open"!==e&&"always-show"!==e&&"disabled"!==e?("content"===e&&this.bodyEl&&(this.bodyEl.textContent=this.getAttribute("content")||""),this.isOpen()&&(this.updatePanelMetadata(),requestAnimationFrame(()=>this.positionPanel()))):this.syncOpenFromAttributes())}resolvedPlacement(){const e=this.getAttribute("position")||this.getAttribute("placement")||"top";return s.includes(e)?e:"top"}resolvedTrigger(){const e=this.getAttribute("trigger")||"click";return r.includes(e)?e:"click"}isControlled(){return this.hasAttribute("open")}isOpen(){return!this.hasAttribute("disabled")&&(!!this.hasAttribute("always-show")||(this.isControlled()?"false"!==this.getAttribute("open"):this.panel?.classList.contains("designbase-wc-popover--visible")??!1))}setOpen(e){this.hasAttribute("disabled")||this.hasAttribute("always-show")||(this.isControlled()?e?this.setAttribute("open",""):this.removeAttribute("open"):e?this.showPanel():this.hidePanel(),this.dispatchEvent(new CustomEvent("db-open-change",{bubbles:!0,composed:!0,detail:{open:e}})),e||this.dispatchEvent(new CustomEvent("db-close",{bubbles:!0,composed:!0})))}syncOpenFromAttributes(){this.hasAttribute("always-show")?this.showPanel():this.isControlled()&&("false"!==this.getAttribute("open")?this.showPanel():this.hidePanel())}clearTimers(){this.showTimer&&clearTimeout(this.showTimer),this.hideTimer&&clearTimeout(this.hideTimer),this.showTimer=void 0,this.hideTimer=void 0}groupOf(e){return e.startsWith("top")?"top":e.startsWith("bottom")?"bottom":e.startsWith("left")?"left":"right"}collectTriggerChildren(){const isInternalNode=e=>e.hasAttribute("data-wc-internal")||"content"===e.getAttribute("slot")||e===this.triggerWrap,e=Array.from(this.children).filter(e=>!isInternalNode(e));return e.length>0?e:Array.from(this.triggerWrap?.children||[]).filter(e=>"content"!==e.getAttribute("slot"))}ensureTriggerWrap(){this.triggerWrap||(this.triggerWrap=document.createElement("span"),this.triggerWrap.className="designbase-wc-popover__trigger",this.triggerWrap.setAttribute("data-wc-internal",""),this.triggerWrap.tabIndex=this.hasAttribute("trigger-id")?-1:0,this.triggerWrap.addEventListener("click",this.handleTriggerClick),this.triggerWrap.addEventListener("mouseenter",this.handleTriggerMouseEnter),this.triggerWrap.addEventListener("mouseleave",this.handleTriggerMouseLeave),this.triggerWrap.addEventListener("focus",this.handleTriggerFocus),this.triggerWrap.addEventListener("blur",this.handleTriggerBlur))}mountTriggerChildren(e){this.triggerWrap&&e.forEach(e=>{e.parentElement!==this.triggerWrap&&this.triggerWrap.append(e)})}collectBodyChildren(){return[...Array.from(this.querySelectorAll(':scope > [slot="content"]')),...Array.from(this.bodyEl?.querySelectorAll(':scope > [slot="content"]')||[])]}bindExternalTrigger(){const e=this.getAttribute("trigger-id");e&&(this.triggerEl=document.getElementById(e),this.triggerEl&&(this.onExternalTriggerClick=()=>{"click"===this.resolvedTrigger()&&this.setOpen(!this.isOpen())},this.triggerEl.addEventListener("click",this.onExternalTriggerClick)))}unbindExternalTrigger(){this.triggerEl&&this.onExternalTriggerClick&&this.triggerEl.removeEventListener("click",this.onExternalTriggerClick),this.triggerEl=null,this.onExternalTriggerClick=null}attachGlobalListeners(){this.onDocMouseDown=e=>{if(!this.isOpen()||"false"===this.getAttribute("close-on-outside-click"))return;const t=e.target;this.panel?.contains(t)||this.triggerWrap?.contains(t)||this.triggerEl?.contains(t)||this.setOpen(!1)},this.onDocKeyDown=e=>{"Escape"===e.key&&this.isOpen()&&"false"!==this.getAttribute("close-on-escape")&&this.setOpen(!1)},document.addEventListener("mousedown",this.onDocMouseDown),document.addEventListener("keydown",this.onDocKeyDown)}detachGlobalListeners(){this.onDocMouseDown&&document.removeEventListener("mousedown",this.onDocMouseDown),this.onDocKeyDown&&document.removeEventListener("keydown",this.onDocKeyDown),this.onDocMouseDown=null,this.onDocKeyDown=null}scheduleOpen(){this.clearTimers();const e="hover"===this.resolvedTrigger()?Math.max(0,Number(this.getAttribute("delay")||0)):0;this.showTimer=setTimeout(()=>this.showPanel(),e)}scheduleClose(){this.clearTimers();const e="hover"===this.resolvedTrigger()?Math.max(0,Number(this.getAttribute("hide-delay")||80)):0;this.hideTimer=setTimeout(()=>this.setOpen(!1),e)}getTriggerRect(){const e=this.triggerEl||this.triggerWrap;return e?.getBoundingClientRect()}flipPlacementIfNeeded(e,t,i){const s=window.innerHeight,r=window.innerWidth,o=this.groupOf(e),n=t.top-i.height-8>=8,a=t.bottom+8+i.height<=s-8,h=t.left-i.width-8>=8,l=t.right+8+i.width<=r-8;return"top"===o&&!n&&a?e.replace(/^top/,"bottom"):"bottom"===o&&!a&&n?e.replace(/^bottom/,"top"):"left"===o&&!h&&l?e.replace(/^left/,"right"):"right"===o&&!l&&h?e.replace(/^right/,"left"):e}applyCoords(e,t,i){let s=0,r=0,o=0,n=0;const a=i.height,h=i.width,l=16;switch(e){case"top":s=t.top-i.height-8,r=t.left+t.width/2-i.width/2,o=a-5,n=h/2-5;break;case"top-start":s=t.top-i.height-8,r=t.left,o=a-5,n=11;break;case"top-end":s=t.top-i.height-8,r=t.right-i.width,o=a-5,n=h-l-5;break;case"bottom":s=t.bottom+8,r=t.left+t.width/2-i.width/2,o=-5,n=h/2-5;break;case"bottom-start":s=t.bottom+8,r=t.left,o=-5,n=11;break;case"bottom-end":s=t.bottom+8,r=t.right-i.width,o=-5,n=h-l-5;break;case"left":s=t.top+t.height/2-i.height/2,r=t.left-i.width-8,o=a/2-5,n=h-5;break;case"left-start":s=t.top,r=t.left-i.width-8,o=11,n=h-5;break;case"left-end":s=t.bottom-i.height,r=t.left-i.width-8,o=a-l-5,n=h-5;break;case"right":s=t.top+t.height/2-i.height/2,r=t.right+8,o=a/2-5,n=-5;break;case"right-start":s=t.top,r=t.right+8,o=11,n=-5;break;case"right-end":s=t.bottom-i.height,r=t.right+8,o=a-l-5,n=-5}const d=window.innerWidth,c=window.innerHeight;return r<8&&(r=8),r+i.width>d-8&&(r=d-i.width-8),s<8&&(s=8),s+i.height>c-8&&(s=c-i.height-8),{top:s,left:r,aTop:o,aLeft:n,placement:e}}positionPanel(){if(!this.panel)return;const e=this.getTriggerRect();if(!e)return;const t=Number(this.getAttribute("max-width")||300);this.panel.style.maxWidth=`${t}px`,this.panel.offsetHeight;const i=this.panel.getBoundingClientRect(),r=this.resolvedPlacement(),o=this.flipPlacementIfNeeded(r,e,i),{top:n,left:a,aTop:h,aLeft:l}=this.applyCoords(o,e,i);this.panel.style.top=`${n}px`,this.panel.style.left=`${a}px`,this.panel.dataset.placementGroup=this.groupOf(o),s.forEach(e=>{this.panel.classList.toggle(`designbase-wc-popover--${e}`,e===o)}),this.arrowEl&&(this.arrowEl.className=`designbase-wc-popover__arrow designbase-wc-popover__arrow--${o}`,this.arrowEl.style.top=`${h}px`,this.arrowEl.style.left=`${l}px`)}revealPanel(){this.panel&&(this.panel.classList.remove("designbase-wc-popover--visible"),this.positionPanel(),this.panel.offsetHeight,this.positionPanel(),this.panel.classList.add("designbase-wc-popover--visible"))}updatePanelMetadata(){if(!this.panel)return;const e=this.getAttribute("size")||"m",t=this.getAttribute("variant")||"default",i=this.resolvedPlacement();this.panel.className=["designbase-wc-popover",`designbase-wc-popover--${e}`,`designbase-wc-popover--${t}`,`designbase-wc-popover--${i}`,this.isOpen()?"designbase-wc-popover--visible":"",this.hasAttribute("disabled")?"designbase-wc-popover--disabled":""].filter(Boolean).join(" ")}ensurePanel(){if(this.panel)return;const t=document.createElement("div");t.className="designbase-wc-popover",t.setAttribute("data-wc-internal",""),t.setAttribute("role","dialog"),t.setAttribute("aria-modal","false"),t.style.position="fixed",t.style.zIndex="9999";const s=document.createElement("div");s.className="designbase-wc-popover__content";const r=document.createElement("div");r.className="designbase-wc-popover__header";const o=document.createElement("h3");o.className="designbase-wc-popover__title";const n=document.createElement("db-button");n.className="designbase-wc-popover__close-button",n.setAttribute("variant","ghost"),n.setAttribute("size","s"),n.setAttribute("icon-only",""),n.setAttribute("start-icon","close"),n.setAttribute("aria-label",i("팝오버 닫기")),n.addEventListener("db-click",e=>{e.stopPropagation(),this.setOpen(!1)}),r.append(o,n),this.bodyEl=document.createElement("div"),this.bodyEl.className="designbase-wc-popover__body",s.append(r,this.bodyEl),t.append(s),"false"!==this.getAttribute("show-arrow")&&(this.arrowEl=document.createElement("div"),this.arrowEl.className=`designbase-wc-popover__arrow designbase-wc-popover__arrow--${this.resolvedPlacement()}`,t.append(this.arrowEl)),this.panel=t,this.panel.querySelector(".designbase-wc-popover__title").textContent=this.getAttribute("title")||"",this.panel.querySelector(".designbase-wc-popover__title").hidden=!this.getAttribute("title"),e(this,t),document.body.append(t),t.addEventListener("mouseenter",()=>{"hover"===this.resolvedTrigger()&&this.clearTimers()}),t.addEventListener("mouseleave",()=>{"hover"===this.resolvedTrigger()&&this.scheduleClose()})}showPanel(){if(this.hasAttribute("disabled"))return;this.ensurePanel(),this.updatePanelMetadata();const e=this.collectBodyChildren();e.length>0?this.bodyEl.replaceChildren(...e):this.bodyEl.textContent=this.getAttribute("content")||"";const t=this.panel.querySelector(".designbase-wc-popover__title");t.textContent=this.getAttribute("title")||"",t.hidden=!this.getAttribute("title"),requestAnimationFrame(()=>{this.revealPanel(),window.addEventListener("scroll",this.handleReposition,{capture:!0,passive:!0}),window.addEventListener("resize",this.handleReposition)})}hidePanel(){this.panel?.classList.remove("designbase-wc-popover--visible"),window.removeEventListener("scroll",this.handleReposition,!0),window.removeEventListener("resize",this.handleReposition),this.hasAttribute("always-show")||this.removePanel()}removePanel(){this.bodyEl?.querySelectorAll(':scope > [slot="content"]').forEach(e=>this.append(e)),this.panel?.remove(),this.panel=void 0,this.bodyEl=void 0,this.arrowEl=void 0}render(){this.ensureTriggerWrap();const e=this.collectTriggerChildren();this.mountTriggerChildren(e);const t=Boolean(this.getAttribute("trigger-id"));this.triggerWrap&&(e.length>0||!t?this.triggerWrap.parentElement!==this&&this.append(this.triggerWrap):this.triggerWrap.parentElement===this&&this.triggerWrap.remove()),this.hasAttribute("always-show")&&this.showPanel()}}customElements.get("db-popover")||customElements.define("db-popover",DbPopover);export{DbPopover};
|
|
@@ -7,10 +7,12 @@ interface DbProgressStepItemData {
|
|
|
7
7
|
disabled?: boolean;
|
|
8
8
|
}
|
|
9
9
|
declare class DbProgressStep extends HTMLElement {
|
|
10
|
+
private unsubscribeLocale?;
|
|
10
11
|
static get observedAttributes(): string[];
|
|
11
12
|
get items(): DbProgressStepItemData[];
|
|
12
13
|
set items(value: DbProgressStepItemData[] | string);
|
|
13
14
|
connectedCallback(): void;
|
|
15
|
+
disconnectedCallback(): void;
|
|
14
16
|
attributeChangedCallback(): void;
|
|
15
17
|
private resolveStatus;
|
|
16
18
|
private iconSize;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dbFormat as
|
|
1
|
+
import{subscribeDbLocale as e,dbFormat as t}from"../core/i18n.js";import{createDbIcon as s}from"./db-icons.js";import{coerceToContract as i}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{PROGRESS_STEP_SIZES as n}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbProgressStep extends HTMLElement{static get observedAttributes(){return["items","size","layout","current-step","clickable","full-width","disabled"]}get items(){try{return JSON.parse(this.getAttribute("items")||"[]")}catch{return[]}}set items(e){this.setAttribute("items","string"==typeof e?e:JSON.stringify(e))}connectedCallback(){this.render(),this.unsubscribeLocale?.(),this.unsubscribeLocale=e(()=>{const e=this.items;this.querySelectorAll(".designbase-wc-progress-step__item").forEach((s,i)=>{const n=s.querySelector(".designbase-wc-progress-step__indicator[aria-label]"),r=e[i];n&&r&&n.setAttribute("aria-label",t("{0} 단계로 이동",[r.title]))})})}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0}attributeChangedCallback(){this.render()}resolveStatus(e,t){const s=t.status??"pending";if("pending"!==s)return s;const i=Number(this.getAttribute("current-step")||0);return e<i?"completed":e===i?"active":"pending"}iconSize(e){return"s"===e?12:"l"===e?20:16}renderIndicatorContent(e,t,i){const n=document.createElement("div");if(n.className="designbase-wc-progress-step__icon","completed"===e)n.append(s("done",this.iconSize(i)));else if("error"===e)n.append(s("warning-filled",this.iconSize(i)));else{const e=document.createElement("span");e.className="designbase-wc-progress-step__number",e.textContent=String(t+1),n.append(e)}return n}handleStepClick(e,t){const s=this.hasAttribute("disabled"),i=this.hasAttribute("clickable");s||e.disabled||!i||this.dispatchEvent(new CustomEvent("db-step-click",{detail:{item:e,index:t},bubbles:!0,composed:!0}))}render(){const e=i(this.getAttribute("size"),n,"m"),s=this.getAttribute("layout")||"horizontal",r=this.hasAttribute("clickable"),a=this.hasAttribute("disabled"),c=this.items;this.className=["designbase-wc-progress-step",`designbase-wc-progress-step--${e}`,`designbase-wc-progress-step--${s}`,r&&"designbase-wc-progress-step--clickable",this.hasAttribute("full-width")&&"designbase-wc-progress-step--full-width",a&&"designbase-wc-progress-step--disabled"].filter(Boolean).join(" "),this.replaceChildren(),c.forEach((s,i)=>{const n=this.resolveStatus(i,s),o=i===c.length-1,d=r&&!a&&!s.disabled,p=r&&(a||Boolean(s.disabled)),l="completed"===(i>0?this.resolveStatus(i-1,c[i-1]):"pending")?"completed":n,b=document.createElement("div");b.className=["designbase-wc-progress-step__item",`designbase-wc-progress-step__item--${n}`,d&&"designbase-wc-progress-step__item--clickable",s.disabled&&"designbase-wc-progress-step__item--disabled"].filter(Boolean).join(" ");const m=document.createElement("div");m.className="designbase-wc-progress-step__indicator-container";const g=document.createElement("div");if(g.className="designbase-wc-progress-step__indicator",p&&(g.setAttribute("role","button"),g.setAttribute("aria-disabled","true")),d?(g.tabIndex=0,g.setAttribute("role","button"),g.setAttribute("aria-label",t("{0} 단계로 이동",[s.title])),g.addEventListener("click",()=>this.handleStepClick(s,i)),g.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),this.handleStepClick(s,i))})):g.tabIndex=-1,"active"===n){const e=document.createElement("div");e.className="designbase-wc-progress-step__pulse",g.append(e)}if(g.append(this.renderIndicatorContent(n,i,e)),m.append(g),!o){const e=document.createElement("div");e.className=["designbase-wc-progress-step__connector",`designbase-wc-progress-step__connector--${l}`].join(" "),m.append(e)}b.append(m);const u=document.createElement("div");u.className="designbase-wc-progress-step__content";const h=document.createElement("div");h.className="designbase-wc-progress-step__header";const _=document.createElement("h3");if(_.className="designbase-wc-progress-step__title",_.textContent=s.title,h.append(_),u.append(h),s.description){const e=document.createElement("p");e.className="designbase-wc-progress-step__description",e.textContent=s.description,u.append(e)}if(s.timestamp){const e=document.createElement("span");e.className="designbase-wc-progress-step__timestamp",e.textContent=s.timestamp,u.append(e)}b.append(u),this.append(b)})}}customElements.get("db-progress-step")||customElements.define("db-progress-step",DbProgressStep);export{DbProgressStep};
|
|
@@ -5,11 +5,14 @@ declare class DbRadio extends HTMLElement {
|
|
|
5
5
|
private visual?;
|
|
6
6
|
private dot?;
|
|
7
7
|
private labelEl?;
|
|
8
|
+
private readonly labelContent;
|
|
8
9
|
private built;
|
|
9
10
|
private userInteracted;
|
|
10
11
|
private resetChecked?;
|
|
11
12
|
private readonly cleanups;
|
|
12
13
|
focus(options?: FocusOptions): void;
|
|
14
|
+
get label(): string;
|
|
15
|
+
set label(value: string);
|
|
13
16
|
get name(): string;
|
|
14
17
|
set name(value: string);
|
|
15
18
|
get value(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{ControlLabel as t}from"../core/control-label.js";import{CleanupBag as e}from"../core/dom.js";import{coerceToContract as s}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{RADIO_SIZES as i}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";class DbRadio extends HTMLElement{constructor(){super(...arguments),this.labelContent=new t(this),this.built=!1,this.userInteracted=!1,this.cleanups=new e,this.handleChange=()=>{if(!this.input||this.disabled||this.readOnly)return;this.userInteracted=!0;const t=this.input.checked;this.removeAttribute("selected"),this.toggleAttribute("checked",t),this.syncGroup(),this.syncVisual(),this.syncClasses(),this.dispatchEvent(new CustomEvent("db-change",{detail:{checked:t,selected:t,value:this.input.value},bubbles:!0,composed:!0}))}}static get observedAttributes(){return["checked","selected","default-checked","default-selected","size","disabled","readonly","required","name","value","label","has-label","aria-label","aria-labelledby","aria-describedby"]}focus(t){this.input?.focus(t)}get label(){return this.labelContent.value}set label(t){this.setAttribute("label",t)}get name(){return this.getAttribute("name")||""}set name(t){this.setAttribute("name",t)}get value(){return this.getAttribute("value")??"on"}set value(t){this.setAttribute("value",t)}get defaultChecked(){return this.hasAttribute("default-checked")||this.hasAttribute("default-selected")}set defaultChecked(t){this.removeAttribute("default-selected"),this.toggleAttribute("default-checked",t)}get defaultSelected(){return this.defaultChecked}set defaultSelected(t){this.defaultChecked=t}upgradeProperties(){for(const t of["checked","selected","defaultChecked","defaultSelected","name","value","label","disabled","readOnly","required","hasLabel","size"]){if(!Object.prototype.hasOwnProperty.call(this,t))continue;const e=this,s=e[t];delete e[t],e[t]=s}}get checked(){return this.input?.checked??(this.hasAttribute("checked")||this.hasAttribute("selected"))}set checked(t){this.userInteracted=!0,this.removeAttribute("selected"),this.toggleAttribute("checked",t),this.input&&(this.input.checked=t,this.syncVisual(),this.syncClasses(),this.syncGroup())}get selected(){return this.checked}set selected(t){this.checked=t}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",t),this.input&&(this.input.disabled=t),this.syncClasses()}get readOnly(){return this.hasAttribute("readonly")}set readOnly(t){this.toggleAttribute("readonly",t),this.input&&(this.input.readOnly=t),this.syncClasses()}get required(){return this.hasAttribute("required")}set required(t){this.toggleAttribute("required",t),this.input&&(this.input.required=t)}get size(){return s(this.getAttribute("size"),i,"m")}set size(t){this.setAttribute("size",t)}connectedCallback(){this.upgradeProperties(),this.style.display="contents",this.built||this.build(),this.labelContent.connect(this.labelEl,()=>this.syncClasses()),this.syncState(),this.input?.form&&this.cleanups.listen(this.input.form,"reset",()=>{window.setTimeout(()=>{this.input&&this.isConnected&&(this.toggleAttribute("checked",this.input.checked),this.removeAttribute("selected"),this.syncClasses())},0)})}disconnectedCallback(){this.cleanups.run(),this.labelContent.disconnect()}attributeChangedCallback(t){if(this.built){if("default-checked"!==t&&"default-selected"!==t||(this.resetChecked=this.hasAttribute("default-checked")||this.hasAttribute("default-selected")),"checked"===t||"selected"===t)return this.userInteracted=!0,this.input&&(this.input.checked=this.hasAttribute("checked")||this.hasAttribute("selected")),this.syncVisual(),this.syncClasses(),void this.syncGroup();this.syncState()}}get hasLabel(){return!this.hasAttribute("has-label")||"false"!==this.getAttribute("has-label")}set hasLabel(t){this.setAttribute("has-label",String(t))}build(){for(this.root=document.createElement("label"),this.root.className="designbase-wc-radio",this.input=document.createElement("input"),this.input.type="radio",this.input.className="designbase-wc-radio__input",this.visual=document.createElement("span"),this.visual.className="designbase-wc-radio__visual",this.visual.setAttribute("aria-hidden","true"),this.dot=document.createElement("span"),this.dot.className="designbase-wc-radio__dot",this.visual.appendChild(this.dot),this.labelEl=document.createElement("span"),this.labelEl.className="designbase-wc-radio__label";this.firstChild;)this.labelEl.appendChild(this.firstChild);this.root.append(this.input,this.visual,this.labelEl),this.appendChild(this.root),this.input.addEventListener("click",t=>{this.readOnly&&t.preventDefault()}),this.input.addEventListener("keydown",t=>{const e=["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"];if(this.readOnly&&(" "===t.key||e.includes(t.key)))return void t.preventDefault();const s=this.groupPeers();if(!e.includes(t.key)||!s.some(t=>t.readOnly))return;const i=s.filter(t=>!t.disabled&&!t.readOnly);if(!i.length)return;t.preventDefault();const a="rtl"===getComputedStyle(this).direction,r="ArrowDown"===t.key||t.key===(a?"ArrowLeft":"ArrowRight"),h=i[(i.indexOf(this)+(r?1:-1)+i.length)%i.length];h.input?.focus(),h.input?.click()}),this.input.addEventListener("change",this.handleChange),this.built=!0}groupPeers(){if(!this.input?.name)return[this];const t=this.getRootNode();return Array.from(t.querySelectorAll("db-radio")).filter(t=>t.input?.name===this.input.name&&t.input?.form===this.input.form)}syncGroup(){if(this.input?.checked&&this.input.name){const t=this.getRootNode();for(const e of t.querySelectorAll("db-radio"))e!==this&&e.input&&e.input.name===this.input.name&&e.input.form===this.input.form&&(e.userInteracted=!0,e.removeAttribute("checked"),e.removeAttribute("selected"),e.syncClasses())}}syncState(){if(!this.root||!this.input||!this.visual)return;this.labelContent.sync();const t=this.hasAttribute("checked")||this.hasAttribute("selected")||!this.userInteracted&&(this.hasAttribute("default-checked")||this.hasAttribute("default-selected"));this.resetChecked??(this.resetChecked=t),this.input.defaultChecked=this.resetChecked,this.input.checked=t,this.input.disabled=this.disabled,this.input.readOnly=this.readOnly,this.input.setAttribute("aria-disabled",String(this.disabled||this.readOnly)),this.input.required=this.required,this.input.name=this.getAttribute("name")||"",this.input.value=this.getAttribute("value")??"on";for(const t of["aria-label","aria-labelledby","aria-describedby"]){const e=this.getAttribute(t);e?this.input.setAttribute(t,e):this.input.removeAttribute(t)}this.hasLabel?this.labelEl?.removeAttribute("hidden"):this.labelEl?.setAttribute("hidden",""),this.syncVisual(),this.syncClasses()}syncVisual(){}syncClasses(){if(!this.root||!this.input)return;const t=i.includes(this.size)?this.size:"m",e=this.hasLabel&&Boolean(this.label.trim());this.root.className=["designbase-wc-radio",`designbase-wc-radio--${t}`,this.input.checked&&"designbase-wc-radio--selected",this.disabled&&"designbase-wc-radio--disabled",this.readOnly&&"designbase-wc-radio--readonly",!e&&"designbase-wc-radio--no-label"].filter(Boolean).join(" ")}}customElements.get("db-radio")||customElements.define("db-radio",DbRadio);export{DbRadio};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
declare class DbRangeSlider extends HTMLElement {
|
|
2
|
+
private unsubscribeLocale?;
|
|
2
3
|
static get observedAttributes(): string[];
|
|
3
4
|
private built;
|
|
4
5
|
private headerEl;
|
|
@@ -8,6 +9,11 @@ declare class DbRangeSlider extends HTMLElement {
|
|
|
8
9
|
private trackEl;
|
|
9
10
|
private fillEl;
|
|
10
11
|
private thumbEls;
|
|
12
|
+
private initialized;
|
|
13
|
+
private reflecting;
|
|
14
|
+
private pointerId;
|
|
15
|
+
private pointerThumb;
|
|
16
|
+
private tooltipResize?;
|
|
11
17
|
private currentValue;
|
|
12
18
|
private currentRange;
|
|
13
19
|
private isDragging;
|
|
@@ -15,15 +21,35 @@ declare class DbRangeSlider extends HTMLElement {
|
|
|
15
21
|
private boundTrackClick;
|
|
16
22
|
private boundPointerMove;
|
|
17
23
|
private boundPointerUp;
|
|
24
|
+
private boundPointerCancel;
|
|
18
25
|
private eventsBound;
|
|
19
26
|
connectedCallback(): void;
|
|
20
27
|
disconnectedCallback(): void;
|
|
21
|
-
attributeChangedCallback(name: string): void;
|
|
28
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
22
29
|
private isStructuralAttribute;
|
|
23
30
|
get value(): number;
|
|
24
31
|
set value(v: number);
|
|
25
32
|
get range(): [number, number] | undefined;
|
|
26
33
|
set range(v: [number, number] | string | undefined);
|
|
34
|
+
get min(): number;
|
|
35
|
+
set min(value: number);
|
|
36
|
+
get max(): number;
|
|
37
|
+
set max(value: number);
|
|
38
|
+
get step(): number;
|
|
39
|
+
set step(value: number);
|
|
40
|
+
get size(): string;
|
|
41
|
+
set size(value: string);
|
|
42
|
+
get variant(): string;
|
|
43
|
+
set variant(value: string);
|
|
44
|
+
get disabled(): boolean;
|
|
45
|
+
set disabled(value: boolean);
|
|
46
|
+
get readOnly(): boolean;
|
|
47
|
+
set readOnly(value: boolean);
|
|
48
|
+
get vertical(): boolean;
|
|
49
|
+
set vertical(value: boolean);
|
|
50
|
+
focus(options?: FocusOptions): void;
|
|
51
|
+
private get bounds();
|
|
52
|
+
private normalizeValues;
|
|
27
53
|
private build;
|
|
28
54
|
private getValuePosition;
|
|
29
55
|
private shouldShowLabel;
|
|
@@ -37,32 +63,35 @@ declare class DbRangeSlider extends HTMLElement {
|
|
|
37
63
|
private isMarkActive;
|
|
38
64
|
private syncVisuals;
|
|
39
65
|
private syncThumbTooltips;
|
|
66
|
+
private fitFloatingText;
|
|
67
|
+
private syncMarkLabelBounds;
|
|
40
68
|
private syncA11y;
|
|
41
69
|
private setThumbPosition;
|
|
42
70
|
private valueToPercent;
|
|
43
71
|
private percentToValue;
|
|
44
|
-
private snapToStep;
|
|
45
72
|
private clamp;
|
|
73
|
+
/** snap-marks: the marks are the only selectable values. */
|
|
74
|
+
private snapStops;
|
|
75
|
+
private adjacentStop;
|
|
46
76
|
private getNumberAttr;
|
|
47
77
|
private normalizeRangeInput;
|
|
48
78
|
private parseRangeAttr;
|
|
49
79
|
private parseMarks;
|
|
80
|
+
private readMarks;
|
|
50
81
|
private parseMarkLabels;
|
|
51
82
|
private isInteractive;
|
|
52
83
|
private getTrackPercent;
|
|
53
84
|
private handleThumbPointerDown;
|
|
54
85
|
private handleTrackClick;
|
|
55
|
-
/**
|
|
56
|
-
* 포인터 이동을 프레임당 1회로 병합한다. preventDefault 를 쓰지 않으므로 안전하다. (PERF-RAF)
|
|
57
|
-
* 메서드가 아니라 필드로 선언해야 rafThrottle 로 감쌀 수 있다.
|
|
58
|
-
*/
|
|
59
86
|
private handlePointerMove;
|
|
60
87
|
private handlePointerUp;
|
|
88
|
+
private cancelDrag;
|
|
61
89
|
private setThumbActive;
|
|
90
|
+
private reflectCurrent;
|
|
62
91
|
private applyDragValue;
|
|
92
|
+
private applyValue;
|
|
63
93
|
private commitValueAtPosition;
|
|
64
94
|
private handleKeyDown;
|
|
65
|
-
private afterKeyboard;
|
|
66
95
|
private dispatchValueChange;
|
|
67
96
|
private dispatchRangeChange;
|
|
68
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{rafThrottle as t}from"../core/dom.js";const e="designbase-wc-range-slider";class DbRangeSlider extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.headerEl=null,this.labelEl=null,this.valuesEl=null,this.containerEl=null,this.trackEl=null,this.fillEl=null,this.thumbEls=[],this.currentValue=50,this.currentRange=[25,75],this.isDragging=!1,this.activeThumb=null,this.boundTrackClick=t=>this.handleTrackClick(t),this.boundPointerMove=t=>this.handlePointerMove(t),this.boundPointerUp=()=>this.handlePointerUp(),this.eventsBound=!1,this.handlePointerMove=t(t=>{if(!this.isDragging||!this.isInteractive())return;const e=this.getTrackPercent(t.clientX,t.clientY),i=this.percentToValue(e);this.applyDragValue(i)})}static get observedAttributes(){return["value","range","min","max","step","size","variant","show-value","show-label","label","value-position","value-fixed","show-thumb-tooltip","show-marks","marks","mark-labels","disabled","readonly","full-width","vertical"]}connectedCallback(){this.built||(this.build(),this.built=!0),this.readAttributeValues(),this.syncClasses(),this.syncDomOrder(),this.syncStructure(),this.syncVisuals(),this.syncA11y(),this.bindEvents()}disconnectedCallback(){this.unbindEvents()}attributeChangedCallback(t){this.built&&(this.readAttributeValues(),this.syncClasses(),this.isStructuralAttribute(t)&&(this.syncDomOrder(),this.syncStructure()),this.syncVisuals(),this.syncA11y())}isStructuralAttribute(t){return["range","show-value","show-label","label","value-position","show-marks","marks","mark-labels","vertical"].includes(t)}get value(){return this.currentValue}set value(t){this.currentValue=this.clamp(t),this.setAttribute("value",String(this.currentValue)),this.syncVisuals()}get range(){if(this.hasAttribute("range"))return[...this.currentRange]}set range(t){if(null==t)return this.removeAttribute("range"),void(this.built&&(this.syncStructure(),this.syncVisuals()));const e=this.normalizeRangeInput(t);if(!e)return;const i=[Math.min(e[0],e[1]),Math.max(e[0],e[1])];this.currentRange=[this.clamp(i[0]),this.clamp(i[1])];const s=`${this.currentRange[0]},${this.currentRange[1]}`;this.getAttribute("range")!==s&&this.setAttribute("range",s),this.built&&this.syncVisuals()}build(){this.classList.add(e),this.headerEl=document.createElement("div"),this.headerEl.className=`${e}__header`,this.labelEl=document.createElement("span"),this.labelEl.className=`${e}__label`,this.valuesEl=document.createElement("div"),this.valuesEl.className=`${e}__values`,this.containerEl=document.createElement("div"),this.containerEl.className=`${e}__container`,this.trackEl=document.createElement("div"),this.trackEl.className=`${e}__track`,this.fillEl=document.createElement("div"),this.fillEl.className=`${e}__fill`,this.trackEl.appendChild(this.fillEl),this.containerEl.appendChild(this.trackEl)}getValuePosition(){const t=this.getAttribute("value-position");return t||(this.shouldShowLabel()?"top":"right")}shouldShowLabel(){return this.hasAttribute("show-label")&&Boolean(this.getAttribute("label")?.trim())}formatValue(t){const e=this.getAttribute("value-fixed");if(null!==e&&""!==e){const i=Number(e);if(Number.isFinite(i))return t.toFixed(i)}return String(t)}syncDomOrder(){if(!this.headerEl||!this.valuesEl||!this.containerEl)return;const t=this.getValuePosition(),e=this.shouldShowLabel(),i=this.hasAttribute("show-value"),s=this.hasAttribute("range");return this.replaceChildren(),this.labelEl&&(this.labelEl.textContent=this.getAttribute("label")?.trim()||""),s||"top"===t?(this.headerEl.replaceChildren(),e&&this.labelEl&&this.headerEl.appendChild(this.labelEl),i&&this.headerEl.appendChild(this.valuesEl),this.headerEl.childElementCount>0&&this.append(this.headerEl),void this.append(this.containerEl)):"bottom"===t?(e&&this.labelEl&&(this.headerEl.replaceChildren(this.labelEl),this.append(this.headerEl)),this.append(this.containerEl),void(i&&this.append(this.valuesEl))):void(i?this.append(this.valuesEl,this.containerEl):this.append(this.containerEl))}bindEvents(){this.eventsBound||(this.trackEl?.addEventListener("click",this.boundTrackClick),this.eventsBound=!0)}unbindEvents(){this.eventsBound&&(this.trackEl?.removeEventListener("click",this.boundTrackClick),document.removeEventListener("pointermove",this.boundPointerMove),document.removeEventListener("pointerup",this.boundPointerUp),this.eventsBound=!1)}readAttributeValues(){const t=this.getNumberAttr("min",0),e=this.getNumberAttr("max",100),i=this.getNumberAttr("step",1);if(this.hasAttribute("range")){const s=this.parseRangeAttr(this.getAttribute("range"));s?this.currentRange=[this.clamp(s[0],t,e,i),this.clamp(s[1],t,e,i)]:this.currentRange.every(Number.isFinite)||(this.currentRange=[25,75])}else this.currentValue=this.clamp(this.getNumberAttr("value",50),t,e,i)}syncClasses(){const t=this.getAttribute("size")||"m",i=this.getAttribute("variant")||"default",s=this.hasAttribute("range"),r=this.getValuePosition(),a=s?"top":r,n=this.hasAttribute("show-marks")&&this.parseMarks().length>0&&Object.keys(this.parseMarkLabels()).length>0,h=[e,`${e}--${t}`,`${e}--${i}`,`${e}--value-${a}`,this.shouldShowLabel()?`${e}--has-label`:"",this.hasAttribute("disabled")?`${e}--disabled`:"",this.hasAttribute("readonly")?`${e}--readonly`:"",this.hasAttribute("full-width")?`${e}--full-width`:"",this.hasAttribute("vertical")?`${e}--vertical`:"",this.hasAttribute("show-thumb-tooltip")?`${e}--show-tooltip`:"",s?`${e}--range`:"",n?`${e}--has-mark-labels`:""].filter(Boolean);if(this.className=h.join(" "),this.trackEl){const t=[`${e}__track`];this.hasAttribute("disabled")&&t.push(`${e}__track--disabled`),this.hasAttribute("readonly")&&t.push(`${e}__track--readonly`),this.trackEl.className=t.join(" ")}}syncStructure(){if(!this.valuesEl||!this.trackEl||!this.fillEl)return;const t=this.hasAttribute("show-value"),i=this.hasAttribute("range"),s=this.hasAttribute("show-marks");if(this.valuesEl.innerHTML="",this.valuesEl.hidden=!t,t)if(i){const t=document.createElement("span");t.className=`${e}__value ${e}__value--min`;const i=document.createElement("span");i.className=`${e}__value-separator`,i.textContent="~",i.setAttribute("aria-hidden","true");const s=document.createElement("span");s.className=`${e}__value ${e}__value--max`,this.valuesEl.append(t,i,s)}else{const t=document.createElement("span");t.className=`${e}__value ${e}__value--single`,this.valuesEl.appendChild(t)}if(this.thumbEls.forEach(t=>t.remove()),this.thumbEls=[],this.trackEl.querySelectorAll(`.${e}__mark`).forEach(t=>t.remove()),s){const t=this.parseMarks();if(t.length>0){const i=this.parseMarkLabels();t.forEach(t=>{const s=document.createElement("div");if(s.className=`${e}__mark`,s.setAttribute("aria-hidden","true"),this.isMarkActive(t)&&s.classList.add(`${e}__mark--active`),this.hasAttribute("vertical")?s.style.bottom=`${this.valueToPercent(t)}%`:s.style.left=`${this.valueToPercent(t)}%`,void 0!==i[t]){const r=document.createElement("span");r.className=`${e}__mark-label`,r.textContent=i[t],s.appendChild(r)}this.trackEl.insertBefore(s,this.fillEl)})}}const r=i?2:1,a=this.hasAttribute("disabled")||this.hasAttribute("readonly");for(let t=0;t<r;t++){const s=document.createElement("div");s.className=`${e}__thumb`,s.setAttribute("role","slider"),s.setAttribute("draggable","false"),s.setAttribute("tabindex",a?"-1":"0");const r=i?0===t?"min":"max":"single";i&&(s.dataset.thumb=r),s.addEventListener("pointerdown",t=>this.handleThumbPointerDown(t,r)),s.addEventListener("keydown",t=>this.handleKeyDown(t,r));const n=document.createElement("span");n.className=`${e}__thumb-tooltip`,n.setAttribute("aria-hidden","true"),n.hidden=!0,s.appendChild(n),this.trackEl.appendChild(s),this.thumbEls.push(s)}}isMarkActive(t){if(this.hasAttribute("range")){const[e,i]=this.currentRange;return t>=e&&t<=i}return t<=this.currentValue}syncVisuals(){if(!this.fillEl)return;const t=this.hasAttribute("range"),i=this.getNumberAttr("min",0),s=this.getNumberAttr("max",100);if(t){const[t,r]=this.currentRange,a=this.valueToPercent(t),n=this.valueToPercent(r);this.hasAttribute("vertical")?(this.fillEl.style.left="",this.fillEl.style.width="",this.fillEl.style.bottom=`${a}%`,this.fillEl.style.height=n-a+"%"):(this.fillEl.style.bottom="",this.fillEl.style.height="",this.fillEl.style.left=`${a}%`,this.fillEl.style.width=n-a+"%"),this.thumbEls[0]&&(this.setThumbPosition(this.thumbEls[0],a),this.thumbEls[0].setAttribute("aria-valuemin",String(i)),this.thumbEls[0].setAttribute("aria-valuemax",String(r)),this.thumbEls[0].setAttribute("aria-valuenow",String(t))),this.thumbEls[1]&&(this.setThumbPosition(this.thumbEls[1],n),this.thumbEls[1].setAttribute("aria-valuemin",String(t)),this.thumbEls[1].setAttribute("aria-valuemax",String(s)),this.thumbEls[1].setAttribute("aria-valuenow",String(r)));const h=this.valuesEl?.querySelector(`.${e}__value--min`),l=this.valuesEl?.querySelector(`.${e}__value--max`);h&&(h.textContent=this.formatValue(t)),l&&(l.textContent=this.formatValue(r))}else{const t=this.valueToPercent(this.currentValue);this.hasAttribute("vertical")?(this.fillEl.style.left="",this.fillEl.style.width="",this.fillEl.style.bottom="0",this.fillEl.style.height=`${t}%`):(this.fillEl.style.bottom="",this.fillEl.style.height="",this.fillEl.style.left="0",this.fillEl.style.width=`${t}%`),this.thumbEls[0]&&(this.setThumbPosition(this.thumbEls[0],t),this.thumbEls[0].setAttribute("aria-valuemin",String(i)),this.thumbEls[0].setAttribute("aria-valuemax",String(s)),this.thumbEls[0].setAttribute("aria-valuenow",String(this.currentValue)));const r=this.valuesEl?.querySelector(`.${e}__value--single`);r&&(r.textContent=this.formatValue(this.currentValue))}this.syncThumbTooltips(),this.trackEl?.querySelectorAll(`.${e}__mark`).forEach(t=>{const i=t instanceof HTMLElement?parseFloat(t.style.left):NaN,s=t instanceof HTMLElement?parseFloat(t.style.bottom):NaN,r=Number.isFinite(i)?i:s;if(!Number.isFinite(r))return;const a=this.percentToValue(r);t.classList.toggle(`${e}__mark--active`,this.isMarkActive(a))})}syncThumbTooltips(){const t=this.hasAttribute("range"),i=this.hasAttribute("show-thumb-tooltip");this.thumbEls.forEach((s,r)=>{const a=s.querySelector(`.${e}__thumb-tooltip`);if(!a)return;if(!i)return void(a.hidden=!0);a.hidden=!1;const n=t?0===r?this.currentRange[0]:this.currentRange[1]:this.currentValue;a.textContent=this.formatValue(n)})}syncA11y(){if(!this.containerEl)return;const t=this.getNumberAttr("min",0),e=this.getNumberAttr("max",100),i=this.hasAttribute("range"),s=this.hasAttribute("disabled"),r=this.hasAttribute("readonly");this.containerEl.removeAttribute("role"),this.containerEl.removeAttribute("tabindex"),["aria-valuemin","aria-valuemax","aria-valuenow","aria-valuetext","aria-disabled","aria-readonly"].forEach(t=>this.containerEl?.removeAttribute(t));const a=this.getAttribute("label")?.trim()||"값";this.thumbEls.forEach((n,h)=>{const l=i?0===h?this.currentRange[0]:this.currentRange[1]:this.currentValue,u=i?`${a} ${0===h?"최소값":"최대값"}`:a;n.setAttribute("aria-label",u),n.setAttribute("aria-valuemin",String(i&&1===h?this.currentRange[0]:t)),n.setAttribute("aria-valuemax",String(i&&0===h?this.currentRange[1]:e)),n.setAttribute("aria-valuenow",String(l)),n.setAttribute("aria-valuetext",String(l)),n.setAttribute("aria-disabled",String(s)),n.setAttribute("aria-readonly",String(r)),n.setAttribute("tabindex",s||r?"-1":"0")})}setThumbPosition(t,e){this.hasAttribute("vertical")?(t.style.left="",t.style.bottom=`${e}%`):(t.style.bottom="",t.style.left=`${e}%`)}valueToPercent(t){const e=this.getNumberAttr("min",0),i=this.getNumberAttr("max",100);return i===e?0:(t-e)/(i-e)*100}percentToValue(t){const e=this.getNumberAttr("min",0),i=this.getNumberAttr("max",100),s=this.getNumberAttr("step",1),r=e+t/100*(i-e);return this.snapToStep(r,e,i,s)}snapToStep(t,e,i,s){const r=Math.round(t/s)*s;return Math.min(i,Math.max(e,r))}clamp(t,e=this.getNumberAttr("min",0),i=this.getNumberAttr("max",100),s=this.getNumberAttr("step",1)){return this.snapToStep(Math.min(i,Math.max(e,t)),e,i,s)}getNumberAttr(t,e){const i=this.getAttribute(t);if(null===i||""===i)return e;const s=Number(i);return Number.isFinite(s)?s:e}normalizeRangeInput(t){if("string"==typeof t)return this.parseRangeAttr(t);if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),i=Number(t[1]);return Number.isFinite(e)&&Number.isFinite(i)?[e,i]:null}parseRangeAttr(t){if(!t)return null;if(t.startsWith("[")){try{const e=JSON.parse(t);if(Array.isArray(e)&&2===e.length){const t=Number(e[0]),i=Number(e[1]);if(Number.isFinite(t)&&Number.isFinite(i))return[t,i]}}catch{return null}return null}const e=t.split(",").map(t=>Number(t.trim()));return 2!==e.length||e.some(t=>!Number.isFinite(t))?null:[e[0],e[1]]}parseMarks(){const t=this.getAttribute("marks");if(!t)return[];if(t.startsWith("[")){try{const e=JSON.parse(t);if(Array.isArray(e))return e.map(t=>Number(t)).filter(t=>Number.isFinite(t))}catch{return[]}return[]}return t.split(",").map(t=>Number(t.trim())).filter(t=>Number.isFinite(t))}parseMarkLabels(){const t=this.getAttribute("mark-labels");if(!t)return{};try{const e=JSON.parse(t),i={};return Object.entries(e).forEach(([t,e])=>{i[Number(t)]=e}),i}catch{return{}}}isInteractive(){return!this.hasAttribute("disabled")&&!this.hasAttribute("readonly")}getTrackPercent(t,e){if(!this.trackEl)return 0;const i=this.trackEl.getBoundingClientRect();if(this.hasAttribute("vertical")){const t=Math.max(i.top,Math.min(i.bottom,e));return(i.bottom-t)/i.height*100}return(Math.max(i.left,Math.min(i.right,t))-i.left)/i.width*100}handleThumbPointerDown(t,e){this.isInteractive()&&(t.preventDefault(),this.isDragging=!0,this.activeThumb=e,this.setThumbActive(e,!0),document.addEventListener("pointermove",this.boundPointerMove),document.addEventListener("pointerup",this.boundPointerUp))}handleTrackClick(t){if(!this.isInteractive()||!this.trackEl)return;if(t.target.closest(`.${e}__thumb`))return;const i=this.getTrackPercent(t.clientX,t.clientY),s=this.percentToValue(i);this.commitValueAtPosition(s)}handlePointerUp(){this.isDragging&&(this.activeThumb&&this.setThumbActive(this.activeThumb,!1),this.isDragging=!1,this.activeThumb=null,document.removeEventListener("pointermove",this.boundPointerMove),document.removeEventListener("pointerup",this.boundPointerUp),this.syncThumbTooltips(),this.hasAttribute("range")?this.setAttribute("range",`${this.currentRange[0]},${this.currentRange[1]}`):this.setAttribute("value",String(this.currentValue)),this.syncA11y())}setThumbActive(t,i){if(this.hasAttribute("range")){const s=this.thumbEls["min"===t?0:1];return void s?.classList.toggle(`${e}__thumb--active`,i)}this.thumbEls[0]?.classList.toggle(`${e}__thumb--active`,i)}applyDragValue(t){const e=this.clamp(t);if(this.hasAttribute("range")){const[t,i]=this.currentRange;if("min"===this.activeThumb)this.currentRange=[Math.min(e,i),i];else if("max"===this.activeThumb)this.currentRange=[t,Math.max(e,t)];else{Math.abs(e-t)<=Math.abs(e-i)?(this.currentRange=[Math.min(e,i),i],this.activeThumb="min"):(this.currentRange=[t,Math.max(e,t)],this.activeThumb="max")}this.syncVisuals(),this.dispatchRangeChange()}else this.currentValue=e,this.syncVisuals(),this.syncA11y(),this.dispatchValueChange()}commitValueAtPosition(t){const e=this.clamp(t);if(this.hasAttribute("range")){const[t,i]=this.currentRange,s=Math.abs(e-t),r=Math.abs(e-i);this.currentRange=s<=r?[Math.min(e,i),i]:[t,Math.max(e,t)],this.setAttribute("range",`${this.currentRange[0]},${this.currentRange[1]}`),this.syncVisuals(),this.dispatchRangeChange()}else this.currentValue=e,this.setAttribute("value",String(this.currentValue)),this.syncVisuals(),this.syncA11y(),this.dispatchValueChange()}handleKeyDown(t,e="single"){if(!this.isInteractive())return;const i=this.getNumberAttr("step",1),s=this.getNumberAttr("min",0),r=this.getNumberAttr("max",100);let a;if(this.hasAttribute("range")&&"single"!==e){const n="min"===e?this.currentRange[0]:this.currentRange[1];switch(t.key){case"ArrowLeft":case"ArrowDown":a=this.clamp(n-i,s,r);break;case"ArrowRight":case"ArrowUp":a=this.clamp(n+i,s,r);break;case"Home":a=s;break;case"End":a=r;break;default:return}const h=[...this.currentRange];if("min"===e?h[0]=a:h[1]=a,h[0]>h[1])return;return t.preventDefault(),this.currentRange=h,void this.afterKeyboard()}if(!this.hasAttribute("range")){switch(t.key){case"ArrowLeft":case"ArrowDown":a=this.clamp(this.currentValue-i,s,r);break;case"ArrowRight":case"ArrowUp":a=this.clamp(this.currentValue+i,s,r);break;case"Home":a=s;break;case"End":a=r;break;default:return}t.preventDefault(),this.currentValue=a,this.afterKeyboard()}}afterKeyboard(){this.hasAttribute("range")?(this.setAttribute("range",`${this.currentRange[0]},${this.currentRange[1]}`),this.syncVisuals(),this.dispatchRangeChange()):(this.setAttribute("value",String(this.currentValue)),this.syncVisuals(),this.syncA11y(),this.dispatchValueChange())}dispatchValueChange(){this.dispatchEvent(new CustomEvent("db-change",{bubbles:!0,composed:!0,detail:{value:this.currentValue}}))}dispatchRangeChange(){this.dispatchEvent(new CustomEvent("db-change",{bubbles:!0,composed:!0,detail:{range:[...this.currentRange]}}))}}customElements.get("db-range-slider")||customElements.define("db-range-slider",DbRangeSlider);export{DbRangeSlider};
|
|
1
|
+
import{rafThrottle as t}from"../core/dom.js";import{setHostClasses as e}from"../core/host-class.js";import{dbUid as i}from"../core/uid.js";import{subscribeDbLocale as s,dbText as r}from"../core/i18n.js";import{sliderBounds as a,sliderPercent as n,sliderValueAt as l,sliderValue as h}from"../core/range-values.js";import{coerceToContract as u}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{RANGE_SLIDER_SIZES as o,RANGE_SLIDER_VARIANTS as c,RANGE_SLIDER_VALUE_POSITIONS as b}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const m="designbase-wc-range-slider";class DbRangeSlider extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.headerEl=null,this.labelEl=null,this.valuesEl=null,this.containerEl=null,this.trackEl=null,this.fillEl=null,this.thumbEls=[],this.initialized=!1,this.reflecting=!1,this.pointerId=null,this.pointerThumb=null,this.currentValue=50,this.currentRange=[25,75],this.isDragging=!1,this.activeThumb=null,this.boundTrackClick=t=>this.handleTrackClick(t),this.boundPointerMove=t=>{t.pointerId===this.pointerId&&this.handlePointerMove(t)},this.boundPointerUp=t=>this.handlePointerUp(t),this.boundPointerCancel=t=>{t.pointerId===this.pointerId&&this.cancelDrag()},this.eventsBound=!1,this.handlePointerMove=t(t=>{this.isDragging&&this.isInteractive()&&t.pointerId===this.pointerId&&this.applyDragValue(this.percentToValue(this.getTrackPercent(t.clientX,t.clientY)))})}static get observedAttributes(){return["value","range","min","max","step","size","variant","show-value","show-label","label","value-position","value-fixed","show-thumb-tooltip","show-marks","marks","mark-labels","snap-marks","disabled","readonly","full-width","vertical","aria-label","aria-labelledby","aria-describedby","label-minimum","label-maximum"]}connectedCallback(){for(const t of["value","range","min","max","step","size","variant","disabled","readOnly","vertical"]){if(!Object.prototype.hasOwnProperty.call(this,t))continue;const e=this,i=e[t];delete e[t],e[t]=i}this.built||(this.build(),this.built=!0),this.readAttributeValues(),this.syncClasses(),this.syncDomOrder(),this.syncStructure(),this.syncVisuals(),this.syncA11y(),this.unsubscribeLocale?.(),this.unsubscribeLocale=s(()=>this.syncA11y()),this.bindEvents(),this.tooltipResize??(this.tooltipResize=new ResizeObserver(()=>{this.isConnected&&(this.syncThumbTooltips(),this.syncMarkLabelBounds())})),this.tooltipResize.observe(this)}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.cancelDrag(),this.unbindEvents(),this.tooltipResize?.disconnect()}attributeChangedCallback(t,e,i){if(!this.built||this.reflecting)return;const s="range"===t&&null===e!=(null===i);this.isInteractive()&&!s&&"vertical"!==t||this.cancelDrag();const r=this.thumbEls.findIndex(t=>t===this.ownerDocument.activeElement),a=this.thumbEls[r];this.readAttributeValues(t),this.syncClasses(),(s||this.isStructuralAttribute(t))&&(this.syncDomOrder(),this.syncStructure()),this.syncVisuals(),this.syncA11y();const n=a?.isConnected?a:r>=0?this.thumbEls[Math.min(r,this.thumbEls.length-1)]:void 0;n&&!this.disabled&&this.ownerDocument.activeElement!==n&&n.focus({preventScroll:!0})}isStructuralAttribute(t){return["min","max","step","show-value","show-label","label","value-position","show-marks","marks","mark-labels","vertical","aria-label","aria-labelledby","aria-describedby","label-minimum","label-maximum"].includes(t)}get value(){return this.built?this.currentValue:this.clamp(this.getNumberAttr("value",50))}set value(t){this.currentValue=this.clamp(Number.isFinite(t)?t:50),this.setAttribute("value",String(this.currentValue)),this.syncVisuals(),this.syncA11y()}get range(){if(!this.hasAttribute("range"))return;const t=this.built?this.currentRange:this.parseRangeAttr(this.getAttribute("range"))??this.currentRange;return this.normalizeValues(t)}set range(t){if(null==t)return this.removeAttribute("range"),void(this.built&&(this.syncStructure(),this.syncVisuals()));const e=this.normalizeRangeInput(t);if(!e)return;this.currentRange=this.normalizeValues(e);const i=`${this.currentRange[0]},${this.currentRange[1]}`;this.getAttribute("range")!==i&&this.setAttribute("range",i),this.built&&(this.syncVisuals(),this.syncA11y())}get min(){return this.getNumberAttr("min",0)}set min(t){this.setAttribute("min",String(t))}get max(){return Math.max(this.min,this.getNumberAttr("max",100))}set max(t){this.setAttribute("max",String(t))}get step(){const t=this.getNumberAttr("step",1);return t>0?t:1}set step(t){this.setAttribute("step",String(t))}get size(){return u(this.getAttribute("size"),o,"m")}set size(t){this.setAttribute("size",t)}get variant(){return u(this.getAttribute("variant"),c,"default")}set variant(t){this.setAttribute("variant",t)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.toggleAttribute("disabled",Boolean(t))}get readOnly(){return this.hasAttribute("readonly")}set readOnly(t){this.toggleAttribute("readonly",Boolean(t))}get vertical(){return this.hasAttribute("vertical")}set vertical(t){this.toggleAttribute("vertical",Boolean(t))}focus(t){this.thumbEls[0]?.focus(t)}get bounds(){return a(this.min,this.max,this.step)}normalizeValues(t){const e=this.clamp(t[0]),i=this.clamp(t[1]);return[Math.min(e,i),Math.max(e,i)]}build(){this.classList.add(m),this.headerEl=document.createElement("div"),this.headerEl.className=`${m}__header`,this.labelEl=document.createElement("span"),this.labelEl.className=`${m}__label`,this.valuesEl=document.createElement("div"),this.valuesEl.className=`${m}__values`,this.containerEl=document.createElement("div"),this.containerEl.className=`${m}__container`,this.trackEl=document.createElement("div"),this.trackEl.className=`${m}__track`,this.fillEl=document.createElement("div"),this.fillEl.className=`${m}__fill`,this.trackEl.appendChild(this.fillEl),this.containerEl.appendChild(this.trackEl)}getValuePosition(){const t=this.getAttribute("value-position");return t?u(t,b,this.shouldShowLabel()?"top":"right"):this.shouldShowLabel()?"top":"right"}shouldShowLabel(){return this.hasAttribute("show-label")&&Boolean(this.getAttribute("label")?.trim())}formatValue(t){const e=this.getAttribute("value-fixed");if(null!==e&&""!==e){const i=Number(e);if(Number.isFinite(i))return t.toFixed(Math.min(100,Math.max(0,Math.trunc(i))))}return String(t)}syncDomOrder(){if(!(this.headerEl&&this.valuesEl&&this.containerEl&&this.labelEl))return;const t=this.getValuePosition(),e=this.shouldShowLabel(),i=this.hasAttribute("show-value"),s=this.hasAttribute("range")||"top"===t;this.labelEl.textContent=this.getAttribute("label")?.trim()||"";const r=[...e?[this.labelEl]:[],...i&&s?[this.valuesEl]:[]];this.headerEl.replaceChildren(...r),this.containerEl.parentNode!==this&&this.append(this.containerEl),i&&!s?"bottom"===t?this.lastElementChild!==this.valuesEl&&this.append(this.valuesEl):this.valuesEl.nextElementSibling!==this.containerEl&&this.insertBefore(this.valuesEl,this.containerEl):s&&i||this.valuesEl.remove();const a=i&&!s&&"bottom"!==t?this.valuesEl:this.containerEl;r.length?this.headerEl.nextElementSibling!==a&&this.insertBefore(this.headerEl,a):this.headerEl.remove();const n=new Set([this.containerEl,...r.length?[this.headerEl]:[],...i&&!s?[this.valuesEl]:[]]);for(const t of Array.from(this.children))n.has(t)||t.remove()}bindEvents(){this.eventsBound||(this.containerEl?.addEventListener("click",this.boundTrackClick),this.eventsBound=!0)}unbindEvents(){this.eventsBound&&(this.containerEl?.removeEventListener("click",this.boundTrackClick),document.removeEventListener("pointermove",this.boundPointerMove),document.removeEventListener("pointerup",this.boundPointerUp),document.removeEventListener("pointercancel",this.boundPointerCancel),this.handlePointerMove.cancel(),this.eventsBound=!1)}readAttributeValues(t){const e=!this.initialized;if((e||"value"===t)&&(this.currentValue=this.clamp(this.getNumberAttr("value",50))),e||"range"===t){const t=this.parseRangeAttr(this.getAttribute("range"))??(this.hasAttribute("range")&&!this.getAttribute("range")?this.parseRangeAttr(this.getAttribute("value")):null);this.currentRange=t?this.normalizeValues(t):this.normalizeValues(this.currentRange)}this.currentValue=this.clamp(this.currentValue),this.currentRange=this.normalizeValues(this.currentRange),this.initialized=!0}syncClasses(){const t=this.size,i=this.variant,s=this.hasAttribute("range"),r=this.getValuePosition(),a=s?"top":r,n=this.hasAttribute("show-marks")&&this.parseMarks().length>0&&Object.keys(this.parseMarkLabels()).length>0,l=[m,`${m}--${t}`,`${m}--${i}`,`${m}--value-${a}`,this.shouldShowLabel()?`${m}--has-label`:"",this.hasAttribute("disabled")?`${m}--disabled`:"",this.hasAttribute("readonly")?`${m}--readonly`:"",this.hasAttribute("full-width")?`${m}--full-width`:"",this.hasAttribute("vertical")?`${m}--vertical`:"",this.hasAttribute("show-thumb-tooltip")?`${m}--show-tooltip`:"",s?`${m}--range`:"",n?`${m}--has-mark-labels`:""].filter(Boolean);if(e(this,l),this.trackEl){const t=[`${m}__track`];this.hasAttribute("disabled")&&t.push(`${m}__track--disabled`),this.hasAttribute("readonly")&&t.push(`${m}__track--readonly`),this.trackEl.className=t.join(" ")}}syncStructure(){if(!this.valuesEl||!this.trackEl||!this.fillEl)return;const t=this.hasAttribute("show-value"),e=this.hasAttribute("range"),i=this.hasAttribute("show-marks");if(this.valuesEl.innerHTML="",this.valuesEl.hidden=!t,t)if(e){const t=document.createElement("span");t.className=`${m}__value ${m}__value--min`;const e=document.createElement("span");e.className=`${m}__value-separator`,e.textContent="~",e.setAttribute("aria-hidden","true");const i=document.createElement("span");i.className=`${m}__value ${m}__value--max`,this.valuesEl.append(t,e,i)}else{const t=document.createElement("span");t.className=`${m}__value ${m}__value--single`,this.valuesEl.appendChild(t)}if(this.trackEl.querySelectorAll(`.${m}__mark`).forEach(t=>t.remove()),i){const t=this.parseMarks();if(t.length>0){const e=this.parseMarkLabels();t.forEach(t=>{const i=document.createElement("div");if(i.className=`${m}__mark`,i.setAttribute("aria-hidden","true"),i.dataset.value=String(t),this.isMarkActive(t)&&i.classList.add(`${m}__mark--active`),this.hasAttribute("vertical")?i.style.bottom=`${this.valueToPercent(t)}%`:i.style.left=`${this.valueToPercent(t)}%`,void 0!==e[t]){const s=document.createElement("span");s.className=`${m}__mark-label`,s.textContent=e[t],i.appendChild(s)}this.trackEl.insertBefore(i,this.fillEl)})}}const s=e?2:1;for(;this.thumbEls.length>s;)this.thumbEls.pop()?.remove();for(;this.thumbEls.length<s;){const t=document.createElement("div");t.className=`${m}__thumb`,t.setAttribute("role","slider"),t.setAttribute("draggable","false");const kind=()=>t.dataset.thumb||"single";t.addEventListener("pointerdown",t=>this.handleThumbPointerDown(t,kind())),t.addEventListener("keydown",t=>this.handleKeyDown(t,kind())),t.addEventListener("lostpointercapture",t=>{t.pointerId===this.pointerId&&this.cancelDrag()});const e=document.createElement("span");e.className=`${m}__thumb-tooltip`,e.setAttribute("aria-hidden","true"),e.hidden=!0,t.append(e),this.trackEl.append(t),this.thumbEls.push(t)}this.thumbEls.forEach((t,i)=>t.dataset.thumb=e?0===i?"min":"max":"single")}isMarkActive(t){if(this.hasAttribute("range")){const[e,i]=this.currentRange;return t>=e&&t<=i}return t<=this.currentValue}syncVisuals(){if(!this.fillEl)return;const t=this.hasAttribute("range"),e=this.min,i=this.max;if(t){const[t,s]=this.currentRange,r=this.valueToPercent(t),a=this.valueToPercent(s);this.hasAttribute("vertical")?(this.fillEl.style.left="",this.fillEl.style.width="",this.fillEl.style.bottom=`${r}%`,this.fillEl.style.height=a-r+"%"):(this.fillEl.style.bottom="",this.fillEl.style.height="",this.fillEl.style.left=`${r}%`,this.fillEl.style.width=a-r+"%"),this.thumbEls[0]&&(this.setThumbPosition(this.thumbEls[0],r),this.thumbEls[0].setAttribute("aria-valuemin",String(e)),this.thumbEls[0].setAttribute("aria-valuemax",String(s)),this.thumbEls[0].setAttribute("aria-valuenow",String(t))),this.thumbEls[1]&&(this.setThumbPosition(this.thumbEls[1],a),this.thumbEls[1].setAttribute("aria-valuemin",String(t)),this.thumbEls[1].setAttribute("aria-valuemax",String(i)),this.thumbEls[1].setAttribute("aria-valuenow",String(s)));const n=this.valuesEl?.querySelector(`.${m}__value--min`),l=this.valuesEl?.querySelector(`.${m}__value--max`);n&&(n.textContent=this.formatValue(t)),l&&(l.textContent=this.formatValue(s))}else{const t=this.valueToPercent(this.currentValue);this.hasAttribute("vertical")?(this.fillEl.style.left="",this.fillEl.style.width="",this.fillEl.style.bottom="0",this.fillEl.style.height=`${t}%`):(this.fillEl.style.bottom="",this.fillEl.style.height="",this.fillEl.style.left="0",this.fillEl.style.width=`${t}%`),this.thumbEls[0]&&(this.setThumbPosition(this.thumbEls[0],t),this.thumbEls[0].setAttribute("aria-valuemin",String(e)),this.thumbEls[0].setAttribute("aria-valuemax",String(i)),this.thumbEls[0].setAttribute("aria-valuenow",String(this.currentValue)));const s=this.valuesEl?.querySelector(`.${m}__value--single`);s&&(s.textContent=this.formatValue(this.currentValue))}this.syncThumbTooltips(),this.syncMarkLabelBounds(),this.trackEl?.querySelectorAll(`.${m}__mark`).forEach(t=>{const e=Number(t.dataset.value);t.classList.toggle(`${m}__mark--active`,this.isMarkActive(e))})}syncThumbTooltips(){const t=this.hasAttribute("range"),e=this.hasAttribute("show-thumb-tooltip");this.thumbEls.forEach((i,s)=>{const r=i.querySelector(`.${m}__thumb-tooltip`);if(!r)return;if(!e)return void(r.hidden=!0);r.hidden=!1;const a=t?0===s?this.currentRange[0]:this.currentRange[1]:this.currentValue;r.textContent=this.formatValue(a),this.fitFloatingText(r)})}fitFloatingText(t){const e=this.getBoundingClientRect();if(!e.width)return;t.style.maxWidth=`${e.width}px`,t.style.marginLeft="0px";const i=t.getBoundingClientRect(),s=i.left<e.left?e.left-i.left:i.right>e.right?e.right-i.right:0;s&&(t.style.marginLeft=`${s}px`)}syncMarkLabelBounds(){this.trackEl?.querySelectorAll(`.${m}__mark-label`).forEach(t=>this.fitFloatingText(t))}syncA11y(){if(!this.containerEl)return;const t=this.min,e=this.max,s=this.hasAttribute("range"),a=this.hasAttribute("disabled"),n=this.hasAttribute("readonly");this.containerEl.removeAttribute("role"),this.containerEl.removeAttribute("tabindex"),["aria-valuemin","aria-valuemax","aria-valuenow","aria-valuetext","aria-disabled","aria-readonly"].forEach(t=>this.containerEl?.removeAttribute(t));const l=this.getAttribute("aria-label")?.trim()||this.getAttribute("label")?.trim()||r("슬라이더 값");this.thumbEls.forEach((h,u)=>{const o=s?0===u?this.currentRange[0]:this.currentRange[1]:this.currentValue,c=0===u?this.getAttribute("label-minimum")||r("범위 최솟값"):this.getAttribute("label-maximum")||r("범위 최댓값"),b=s?`${l} ${c}`:l;h.setAttribute("aria-label",b);const m=this.getAttribute("aria-labelledby");if(m)if(s){const t=h.querySelector("[data-range-endpoint]")??document.createElement("span");t.dataset.rangeEndpoint="",t.hidden=!0,t.id||(t.id=i("slider-endpoint")),t.textContent=c,t.parentNode||h.append(t),h.setAttribute("aria-labelledby",m+" "+t.id)}else h.setAttribute("aria-labelledby",m);else h.removeAttribute("aria-labelledby");const d=this.getAttribute("aria-describedby");d?h.setAttribute("aria-describedby",d):h.removeAttribute("aria-describedby"),h.setAttribute("aria-orientation",this.vertical?"vertical":"horizontal"),h.setAttribute("aria-valuemin",String(s&&1===u?this.currentRange[0]:t)),h.setAttribute("aria-valuemax",String(s&&0===u?this.currentRange[1]:e)),h.setAttribute("aria-valuenow",String(o)),h.setAttribute("aria-valuetext",this.formatValue(o)),h.setAttribute("aria-disabled",String(a)),h.setAttribute("aria-readonly",String(n)),h.setAttribute("tabindex",a?"-1":"0")})}setThumbPosition(t,e){this.hasAttribute("vertical")?(t.style.left="",t.style.bottom=`${e}%`):(t.style.bottom="",t.style.left=`${e}%`)}valueToPercent(t){return n(t,this.bounds)}percentToValue(t){return l(t,this.bounds)}clamp(t,e=this.min,i=this.max,s=this.step){const r=this.snapStops();return r.length>0&&Number.isFinite(t)?r.reduce((e,i)=>Math.abs(i-t)<Math.abs(e-t)?i:e,r[0]):h(t,a(e,i,s))}snapStops(){return this.hasAttribute("snap-marks")?this.parseMarks():[]}adjacentStop(t,e){const i=this.snapStops();return(e>0?i.find(e=>e>t):[...i].reverse().find(e=>e<t))??t}getNumberAttr(t,e){const i=this.getAttribute(t);if(null===i||""===i)return e;const s=Number(i);return Number.isFinite(s)?s:e}normalizeRangeInput(t){if("string"==typeof t)return this.parseRangeAttr(t);if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),i=Number(t[1]);return Number.isFinite(e)&&Number.isFinite(i)?[e,i]:null}parseRangeAttr(t){if(!t)return null;if(t.startsWith("[")){try{const e=JSON.parse(t);if(Array.isArray(e)&&2===e.length){const t=Number(e[0]),i=Number(e[1]);if(Number.isFinite(t)&&Number.isFinite(i))return[t,i]}}catch{return null}return null}const e=t.split(",").map(t=>Number(t.trim()));return 2!==e.length||e.some(t=>!Number.isFinite(t))?null:[e[0],e[1]]}parseMarks(){return[...new Set(this.readMarks())].filter(t=>t>=this.min&&t<=this.max).sort((t,e)=>t-e)}readMarks(){const t=this.getAttribute("marks");if(!t)return[];if(t.startsWith("[")){try{const e=JSON.parse(t);if(Array.isArray(e))return e.map(t=>Number(t)).filter(t=>Number.isFinite(t))}catch{return[]}return[]}return t.split(",").map(t=>Number(t.trim())).filter(t=>Number.isFinite(t))}parseMarkLabels(){const t=this.getAttribute("mark-labels");if(!t)return{};try{const e=JSON.parse(t);if(!e||"object"!=typeof e||Array.isArray(e))return{};const i={};return Object.entries(e).forEach(([t,e])=>{!Number.isFinite(Number(t))||"string"!=typeof e&&"number"!=typeof e||(i[Number(t)]=String(e))}),i}catch{return{}}}isInteractive(){return!this.hasAttribute("disabled")&&!this.hasAttribute("readonly")}getTrackPercent(t,e){if(!this.trackEl)return 0;const i=this.trackEl.getBoundingClientRect();if(!i.width||!i.height)return 0;if(this.hasAttribute("vertical")){const t=Math.max(i.top,Math.min(i.bottom,e));return(i.bottom-t)/i.height*100}return(Math.max(i.left,Math.min(i.right,t))-i.left)/i.width*100}handleThumbPointerDown(t,e){if(this.isInteractive()&&0===t.button&&!1!==t.isPrimary&&!this.isDragging){t.preventDefault(),this.isDragging=!0,this.pointerId=t.pointerId,this.activeThumb=e,this.pointerThumb=t.currentTarget,this.pointerThumb.focus({preventScroll:!0}),this.setThumbActive(e,!0);try{this.pointerThumb.setPointerCapture(t.pointerId)}catch{}document.addEventListener("pointermove",this.boundPointerMove),document.addEventListener("pointerup",this.boundPointerUp),document.addEventListener("pointercancel",this.boundPointerCancel)}}handleTrackClick(t){this.isInteractive()&&this.trackEl&&!t.target.closest(`.${m}__thumb`)&&this.commitValueAtPosition(this.percentToValue(this.getTrackPercent(t.clientX,t.clientY)))}handlePointerUp(t){this.isDragging&&t.pointerId===this.pointerId&&(this.handlePointerMove.cancel(),this.isInteractive()&&this.applyDragValue(this.percentToValue(this.getTrackPercent(t.clientX,t.clientY))),this.cancelDrag())}cancelDrag(){this.handlePointerMove.cancel(),this.activeThumb&&this.setThumbActive(this.activeThumb,!1);const t=this.pointerThumb,e=this.pointerId;this.isDragging=!1,this.activeThumb=null,this.pointerId=null,this.pointerThumb=null,document.removeEventListener("pointermove",this.boundPointerMove),document.removeEventListener("pointerup",this.boundPointerUp),document.removeEventListener("pointercancel",this.boundPointerCancel);try{t&&null!==e&&t.hasPointerCapture(e)&&t.releasePointerCapture(e)}catch{}}setThumbActive(t,e){if(this.hasAttribute("range")){const i=this.thumbEls["min"===t?0:1];return void i?.classList.toggle(`${m}__thumb--active`,e)}this.thumbEls[0]?.classList.toggle(`${m}__thumb--active`,e)}reflectCurrent(){this.reflecting=!0;try{const t=this.hasAttribute("range")?"range":"value",e="range"===t?this.currentRange.join(","):String(this.currentValue);this.getAttribute(t)!==e&&this.setAttribute(t,e)}finally{this.reflecting=!1}}applyDragValue(t){this.applyValue(t,this.activeThumb??"single")}applyValue(t,e){const i=this.clamp(t);if(this.hasAttribute("range")){const[t,s]=this.currentRange,r="min"===e?[Math.min(i,s),s]:[t,Math.max(i,t)];if(r[0]===t&&r[1]===s)return;this.currentRange=r}else{if(i===this.currentValue)return;this.currentValue=i}this.reflectCurrent(),this.syncVisuals(),this.syncA11y(),this.hasAttribute("range")?this.dispatchRangeChange():this.dispatchValueChange()}commitValueAtPosition(t){const e=this.hasAttribute("range")?Math.abs(t-this.currentRange[0])<=Math.abs(t-this.currentRange[1])?"min":"max":"single";this.thumbEls["max"===e?1:0]?.focus({preventScroll:!0}),this.applyValue(t,e)}handleKeyDown(t,e="single"){if(!this.isInteractive())return;const i=this.hasAttribute("range")?this.currentRange["max"===e?1:0]:this.currentValue;let s;if(this.snapStops().length>0){switch(t.key){case"ArrowLeft":case"ArrowDown":case"PageDown":s=this.adjacentStop(i,-1);break;case"ArrowRight":case"ArrowUp":case"PageUp":s=this.adjacentStop(i,1);break;case"Home":s=this.min;break;case"End":s=this.max;break;default:return}return t.preventDefault(),void this.applyValue(s,e)}switch(t.key){case"ArrowLeft":case"ArrowDown":s=i-this.step;break;case"ArrowRight":case"ArrowUp":s=i+this.step;break;case"PageDown":s=i-10*this.step;break;case"PageUp":s=i+10*this.step;break;case"Home":s=this.min;break;case"End":s=this.max;break;default:return}t.preventDefault(),this.applyValue(s,e)}dispatchValueChange(){this.dispatchEvent(new CustomEvent("db-change",{bubbles:!0,composed:!0,detail:{value:this.currentValue}}))}dispatchRangeChange(){const t=[...this.currentRange];for(const e of["db-change","db-range-change"])this.dispatchEvent(new CustomEvent(e,{bubbles:!0,composed:!0,detail:{range:[...t]}}))}}customElements.get("db-range-slider")||customElements.define("db-range-slider",DbRangeSlider);export{DbRangeSlider};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{subscribeDbLocale as e,t,getDbLocale as s}from"../core/i18n.js";import{createDbIcon as i}from"./db-icons.js";import{rafThrottle as r}from"../core/dom.js";import{coerceToContract as a}from"../node_modules/@designbasekorea/ui-contracts/dist/primitives.js";import{RATING_SIZES as n,RATING_VARIANTS as o}from"../node_modules/@designbasekorea/ui-contracts/dist/components.js";const l=n,c=o,h=["stars","number","both","reviews","detailed"],g=["star","number","percentage","text"],u=["primary","secondary","success","warning","error","custom"];class DbRating extends HTMLElement{constructor(){super(...arguments),this.hoverValue=null,this.starsEl=null,this.handlePointerMove=r(e=>{if(!this.isInteractive()||!this.getBooleanAttr("hover-effect",!0))return;const t=e.target?.closest(".designbase-wc-rating__star");if(!t||!this.contains(t))return;const s=Number(t.dataset.index);if(!Number.isFinite(s))return;const i=this.getNumberAttr("max-value",5),r=this.getPointerValue(s,e.clientX,t,i);this.hoverValue!==r&&(this.hoverValue=r,this.classList.toggle("designbase-wc-rating--hovering",!0),this.refreshStars(),this.dispatchEvent(new CustomEvent("db-hover",{detail:{value:r},bubbles:!0,composed:!0})))}),this.handlePointerLeave=()=>{null!==this.hoverValue&&(this.hoverValue=null,this.classList.remove("designbase-wc-rating--hovering"),this.refreshStars())},this.handleClick=e=>{if(!this.isInteractive())return;const t=e.target?.closest(".designbase-wc-rating__star");if(!t||!this.contains(t))return;e.preventDefault();const s=Number(t.dataset.index);if(!Number.isFinite(s))return;const i=this.getNumberAttr("max-value",5),r=this.getPointerValue(s,e.clientX,t,i);this.hoverValue=null,this.classList.remove("designbase-wc-rating--hovering"),this.setAttribute("value",String(r)),this.dispatchEvent(new CustomEvent("db-change",{detail:{value:r},bubbles:!0,composed:!0})),this.render()}}static get observedAttributes(){return["value","max-value","size","variant","type","display","review-count","rating-text","review-text","allow-half","readonly","disabled","clickable","color","custom-color","animated","hover-effect"]}connectedCallback(){this.addEventListener("mousemove",this.handlePointerMove),this.addEventListener("mouseleave",this.handlePointerLeave),this.addEventListener("click",this.handleClick),this.render(),this.unsubscribeLocale?.(),this.unsubscribeLocale=e(()=>this.render())}disconnectedCallback(){this.unsubscribeLocale?.(),this.unsubscribeLocale=void 0,this.removeEventListener("mousemove",this.handlePointerMove),this.removeEventListener("mouseleave",this.handlePointerLeave),this.removeEventListener("click",this.handleClick)}attributeChangedCallback(){this.isConnected&&this.render()}getNumberAttr(e,t){const s=this.getAttribute(e);if(null===s||""===s)return t;const i=Number(s);return Number.isFinite(i)?i:t}getBooleanAttr(e,t=!1){if(!this.hasAttribute(e))return t;const s=this.getAttribute(e);return""===s||"true"===s}getOption(e,t,s){const i=this.getAttribute(e);return i&&t.includes(i)?i:s}normalizeSize(e){return"xs"===e||"s"===e?"s":"xl"===e||"l"===e?"l":"m"===e?"m":a(e,l,"m")}getStarIconSize(){const e=this.normalizeSize(this.getAttribute("size"));return"s"===e?16:"l"===e?24:20}supportsHalfSteps(){return this.getBooleanAttr("allow-half")||this.getBooleanAttr("clickable")}isInteractive(){return this.getBooleanAttr("clickable")&&!this.getBooleanAttr("readonly")&&!this.getBooleanAttr("disabled")}getStarFill(e,t,s){const i=e+1;return t>=i?1:s&&t>=i-.5?.5:0}getPointerValue(e,t,s,i){const r=s.getBoundingClientRect();let a;return a=this.supportsHalfSteps()&&t-r.left<r.width/2?e+.5:e+1,a/5*i}formatRating(e,s,i,r){const a=e/s*5;return"percentage"===i?`${Math.round(e/s*100)}%`:"number"===i?r?a.toFixed(1):String(Math.round(a)):"text"===i?t(a>=4.5?"rating.high":a>=3?"rating.medium":"rating.low"):`${a.toFixed(1)}/5`}updateStarElement(e,t,s,r,a){e.className=["designbase-wc-rating__star",0===t&&"designbase-wc-rating__star--empty",t>0&&a&&"designbase-wc-rating__star--hover-preview",r&&"designbase-wc-rating__star--clickable",this.getBooleanAttr("animated")&&"designbase-wc-rating__star--animated"].filter(Boolean).join(" "),e.dataset.index=String(s);const n=1===t?"star-filled":.5===t?"star-half":"star",o=this.getStarIconSize(),l=e.querySelector("svg");l?.getAttribute("data-designbase-icon")===n&&l.getAttribute("width")===String(o)||e.replaceChildren(i(n,o))}refreshStars(){if(!this.starsEl)return;const e=this.getNumberAttr("value",0),t=this.getNumberAttr("max-value",5),s=this.getBooleanAttr("allow-half",!1),i=this.getBooleanAttr("hover-effect",!0),r=null!==this.hoverValue&&i,a=(r?this.hoverValue:e)/t*5,n=this.isInteractive(),o=s||r,l=Array.from(this.starsEl.querySelectorAll(":scope > .designbase-wc-rating__star"));for(let e=0;e<5;e+=1){const t=this.getStarFill(e,a,o),s=r&&t>0,i=l[e]??document.createElement("span");i.setAttribute("aria-hidden","true"),this.updateStarElement(i,t,e,n,s),l[e]||this.starsEl.append(i)}for(let e=l.length-1;e>=5;e-=1)l[e]?.remove()}render(){const e=this.getNumberAttr("value",0),i=this.getNumberAttr("max-value",5),r=this.normalizeSize(this.getAttribute("size")),a=this.getOption("variant",c,"default"),n=this.getOption("type",g,"star"),o=this.getOption("display",h,"stars"),l=this.getOption("color",u,"primary"),d=this.getNumberAttr("review-count",0),m=this.getBooleanAttr("allow-half",!1),b=this.getBooleanAttr("readonly",!1),v=this.getBooleanAttr("disabled",!1),p=this.getBooleanAttr("clickable",!1),f=this.getBooleanAttr("hover-effect",!0),w=null!==this.hoverValue&&f;this.className=["designbase-wc-rating",`designbase-wc-rating--size-${r}`,`designbase-wc-rating--variant-${a}`,`designbase-wc-rating--type-${n}`,`designbase-wc-rating--display-${o}`,`designbase-wc-rating--color-${l}`,b&&"designbase-wc-rating--readonly",v&&"designbase-wc-rating--disabled",p&&"designbase-wc-rating--clickable",this.getBooleanAttr("animated")&&"designbase-wc-rating--animated",w&&"designbase-wc-rating--hovering"].filter(Boolean).join(" ");const A=this.getAttribute("custom-color");"custom"===l&&A?this.style.setProperty("--rating-color",A):this.style.removeProperty("--rating-color");let _=this.querySelector(':scope > [role="img"]');_||(_=document.createElement("div"),this.replaceChildren(_)),_.setAttribute("role","img"),_.setAttribute("aria-label",t("rating.label").replace("{value}",this.formatRating(e,i,n,m)));if("stars"===o||"both"===o||"detailed"===o){const e=_.querySelectorAll(":scope > .designbase-wc-rating__stars");e.forEach((e,t)=>{t>0&&e.remove()});const t=e[0];t?this.starsEl=t:(this.starsEl=document.createElement("div"),this.starsEl.className="designbase-wc-rating__stars",_.prepend(this.starsEl)),this.refreshStars()}else this.starsEl&&(this.starsEl.remove(),this.starsEl=null);const E=this.getAttribute("rating-text")||this.formatRating(e,i,n,m);let S=_.querySelector(".designbase-wc-rating__number-container");if("number"===o||"both"===o){if(!S){S=document.createElement("div"),S.className="designbase-wc-rating__number-container";const e=document.createElement("span");e.className="designbase-wc-rating__number",S.append(e),_.append(S)}const e=S.querySelector(".designbase-wc-rating__number");e&&(e.textContent=E)}else S?.remove();let y=_.querySelector(".designbase-wc-rating__review-count");if("reviews"===o||"detailed"===o){const e=this.getAttribute("review-text")||(d>0?t(1===d?"rating.review":"rating.reviews").replace("{count}",d.toLocaleString("ko"===s()?"ko-KR":"en-US")):"");e?(y||(y=document.createElement("span"),y.className="designbase-wc-rating__review-count",_.append(y)),y.textContent=e):y?.remove()}else y?.remove()}}customElements.get("db-rating")||customElements.define("db-rating",DbRating);export{DbRating};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
declare class DbSearchBar extends HTMLElement {
|
|
2
|
+
private unsubscribeLocale?;
|
|
2
3
|
static get observedAttributes(): string[];
|
|
3
4
|
private input?;
|
|
4
5
|
private clearButton?;
|
|
@@ -29,6 +30,7 @@ declare class DbSearchBar extends HTMLElement {
|
|
|
29
30
|
private clearSuggestionInterval;
|
|
30
31
|
private syncSuggestionRolling;
|
|
31
32
|
private syncPlaceholder;
|
|
33
|
+
private syncLocale;
|
|
32
34
|
private syncValueState;
|
|
33
35
|
private syncAttributes;
|
|
34
36
|
private bindGlobalShortcut;
|