@leechanyong/ispark-ui 0.2.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 ADDED
@@ -0,0 +1,81 @@
1
+ # Changelog
2
+
3
+ 본 프로젝트는 [Keep a Changelog](https://keepachangelog.com/ko/) 형식과 [Semantic Versioning](https://semver.org/lang/ko/)을 따릅니다.
4
+
5
+ ## [0.2.0] - 2026-05-06
6
+
7
+ ### Added
8
+ - **공용 디자인 토큰 시스템** — `src/styles/tokens/_size.scss`, `_shape.scss`. 폼/액션 컴포넌트가 공유하므로 `<UiInput size="md">` + `<UiButton size="md">`가 검색바에서 자동 정렬.
9
+ - `$size-{xs,sm,md,lg,auth}-{height,icon,font,padding-x}` 변수.
10
+ - `$shape-{rounded,pill,circle}` 변수.
11
+ - `$sizes`, `$shapes` SCSS map (반복 처리용).
12
+ - **TS 타입 export** — `SIZES`, `INPUT_SIZES`, `SHAPES` 키 배열 + `Size`, `InputSize`, `Shape` 타입을 라이브러리 entry에서 export.
13
+
14
+ ### UiButton v0.2.0
15
+ - **size 4단계** — `xs`(24px) 추가 (기존 sm/md/lg 유지).
16
+ - **`shape`** 신규 prop — `rounded` / `pill` / `circle`. circle은 iconOnly 전용.
17
+ - **`iconSize`** 신규 prop — 미지정 시 size 따라가고, 명시 시 override.
18
+ - **`as="a"` + `target="_blank"`** 시 `rel="noopener noreferrer"` 자동 부여 (보안).
19
+ - **type prop에서 `'reset'` 제거** — 사용처 0건. `'button' | 'submit'`만 유지.
20
+ - 슬롯 아이콘 사이즈를 컴포넌트 size에 맞춰 자동 적용 (`:deep()` + `:not([class*='size-'])`).
21
+ - shape="circle" + iconOnly=false 조합 시 dev 경고.
22
+ - 자동 테스트 8 → 17개.
23
+
24
+ ### UiInput v0.2.0 + v0.2.1 fix
25
+ - **size 4단계** sm/md/lg/auth — 모두 공용 토큰 사용.
26
+ - padding-x 토큰화 — 기존 모든 size 10px 통일에서 sm 10/md 12/lg 16/auth 10 차등.
27
+ - **`shape`** 신규 prop — `rounded` / `pill` (검색바). circle은 입력에 어색하여 제외.
28
+ - **`iconSize`** 신규 prop — UiButton과 동일 패턴.
29
+ - **`required`**, **`autocomplete`**, **`searchAriaLabel`** 신규 prop.
30
+ - **IME composition 안전 처리** — `compositionupdate` 직접 sanitize 제거. `compositionstart/end` + `isComposing` 플래그로 한글 자음 분리/stale value/중복 emit 방지.
31
+ - **blur clamp+step 순서 수정** — step 반올림 후 min/max 재-clamp. 예: min=0 max=1 step=0.6 value=1 → 1.2 emit되던 버그 → 1로 정정.
32
+ - **a11y 강화**:
33
+ - `inheritAttrs: false` + `useAttrs`로 native attrs(`aria-*`, `data-*`, `role` 등)를 input에 forward (wrapper 누수 차단).
34
+ - `desc` → input의 `aria-describedby`로 자동 연결 (Vue 3.5 `useId` 사용, SSR 안전).
35
+ - 검색 아이콘 `<span @click>` → `<button type="button" :disabled>` (키보드 접근).
36
+ - `type="search"` 시 input에 `role="searchbox"` 부여.
37
+ - **inputmode 분기**: `numberOnly` 단독이면 `numeric`, `allowDecimal`/`allowNegative` 시 `decimal`.
38
+ - **타입 정합 강화**: `update:modelValue` 타입을 `string` → `string | number`로 확장. `modelValue`가 number면 number로 emit.
39
+ - enter / search emit 시 `props.modelValue` 대신 DOM의 `input.value` 사용 (stale 방지).
40
+ - `decimals` validation — 0 이상 정수 외엔 무시 + dev 경고.
41
+ - `min/max/step` + `numberOnly=false` 조합 시 dev 경고.
42
+ - autofill 흰 배경 강제 모든 size 적용 (기존 auth-only).
43
+ - 자동 테스트 10 → 29개.
44
+
45
+ ### Storybook 개선
46
+ - **Playground source.transform 도입** — Controls 변경 시 Show Code 실시간 동기. 기본값과 다른 prop만 출력. iconLeft/iconRight/label 데모 control은 slot 패턴으로 변환.
47
+ - argTypes에 `mapping` 사용으로 `'(자동)'`/`'(없음)'` 라벨이 reactive prop change 보장.
48
+ - UiButton: AllShapes 신규 / AllSizes 4단계 / AsLink target=\_blank 데모.
49
+ - UiInput: AllShapes 신규 / Playground transform 적용.
50
+ - 모든 props에 JSDoc — Storybook Controls 패널 설명 자동 추출.
51
+
52
+ ### Migration notes
53
+ - `UiButton type="reset"` 제거 — 사용처 0건이라 사실상 무영향.
54
+ - `UiInput` md/lg 사용처는 padding-x가 좌우 4-6px씩 늘어남 — 검색바 톤 개선.
55
+ - emit 타입 `string | number`로 확장 — number prop을 쓰던 부모는 자동 number 수신.
56
+
57
+ ## [Unreleased]
58
+
59
+ ### Changed
60
+ - **scope `@box3101` → `@leechanyong`** 으로 변경 (GitHub은 box3101, npmjs는 leechanyong username). 패키지 import 경로 변경됨.
61
+ - **registry: GitHub Packages → npmjs.com** 으로 전환. 진짜 anonymous install 가능 (`.npmrc` 설정 불필요).
62
+ - GitHub Actions 워크플로우: `NPM_TOKEN` 시크릿 사용.
63
+ - README 설치 가이드 1줄로 단순화 (`npm install @leechanyong/ispark-ui`).
64
+ - **public 전환** — repo + package 모두 public.
65
+ - 라이센스 `UNLICENSED` → **`MIT`** 변경. `LICENSE` 파일 추가.
66
+
67
+ ## [0.1.0] - 2026-04-28
68
+
69
+ ### Added
70
+ - 초기 라이브러리 셋업 (Vue 3 + Vite + Storybook + Vitest)
71
+ - **UiButton** 컴포넌트
72
+ - variant 4종: `primary` / `secondary` / `ghost` / `danger`
73
+ - size 3종: `sm` (28px) / `md` (32px) / `lg` (40px)
74
+ - states: `disabled` / `loading` (스피너 사이즈 자동) / `fullWidth` / `iconOnly`
75
+ - polymorphic: `as="button" | "a"` (링크로 사용 가능)
76
+ - 안전성: `type="button"` 기본값, `as="a"` + `disabled` 시 `aria-disabled` + `tabindex=-1`
77
+ - 접근성: `iconOnly` + `ariaLabel` 강제 (dev 콘솔 경고)
78
+ - 외부 메서드: `defineExpose({ focus, blur, el })`
79
+ - 디자인 토큰 시스템 — CSS 변수로 런타임 테마 오버라이드 가능
80
+ - 아이콘 시스템 — 10종 SVG (plus/edit/trashcan/close/search/check/arrow-right/download/chevron-down/refresh), base64 인라인으로 self-contained
81
+ - 자동 테스트 8개 (vitest) + Storybook 8 stories + autodocs
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 box3101 <tony.at.cp@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # @leechanyong/ispark-ui
2
+
3
+ Vue 3 + Vite + Storybook 기반 디자인 시스템 UI 라이브러리.
4
+
5
+ > ⚠️ **테스트 단계 (v0.1.x)** — API가 자주 바뀔 수 있습니다. 프로덕션에서 사용 시 버전 고정 권장.
6
+
7
+ ## 설치
8
+
9
+ ### Git URL 직접 설치 (현재 권장 — 인증 불필요)
10
+
11
+ ```bash
12
+ # 최신 main 브랜치
13
+ npm install git+https://github.com/box3101/ispark-ui.git
14
+
15
+ # 또는 특정 태그 (안정 버전 고정)
16
+ npm install git+https://github.com/box3101/ispark-ui.git#v0.1.4
17
+
18
+ # package.json에 명시
19
+ # "@leechanyong/ispark-ui": "github:box3101/ispark-ui#v0.1.4"
20
+ ```
21
+
22
+ 설치 시 자동으로 빌드(`prepare` 훅)되어 바로 사용 가능합니다.
23
+
24
+ ### npm registry 설치 (예정 — 미정)
25
+
26
+ ```bash
27
+ # 향후 npmjs.com 또는 GitHub Packages publish 후 가능
28
+ npm install @leechanyong/ispark-ui
29
+ ```
30
+
31
+ ## 사용
32
+
33
+ ### 컴포넌트 import
34
+
35
+ ```vue
36
+ <script setup lang="ts">
37
+ import { UiButton } from '@leechanyong/ispark-ui'
38
+ import '@leechanyong/ispark-ui/style.css' // 글로벌 스타일 1회 import (앱 진입점에서)
39
+ </script>
40
+
41
+ <template>
42
+ <UiButton variant="primary" @click="handleSave">저장</UiButton>
43
+ </template>
44
+ ```
45
+
46
+ ### 글로벌 스타일은 앱 진입점에서 1회만
47
+
48
+ ```ts
49
+ // main.ts (Vue) 또는 app.vue (Nuxt)
50
+ import '@leechanyong/ispark-ui/style.css'
51
+ ```
52
+
53
+ 이 1줄로 다음이 한 번에 적용됩니다:
54
+ - CSS 변수 (`--color-primary` 등 — 테마 오버라이드 가능)
55
+ - 아이콘 클래스 (`.icon-plus`, `.icon-edit` 등 — 10종 base64 인라인)
56
+ - 기본 reset
57
+
58
+ ## 컴포넌트
59
+
60
+ ### UiButton
61
+
62
+ ```vue
63
+ <UiButton variant="primary" size="md" @click="...">저장</UiButton>
64
+
65
+ <!-- variant: primary | secondary | ghost | danger -->
66
+ <!-- size: sm(28px) | md(32px) | lg(40px) -->
67
+
68
+ <!-- 아이콘 -->
69
+ <UiButton variant="primary">
70
+ <template #icon-left><i class="icon-plus size-16" /></template>
71
+ Agent 추가
72
+ </UiButton>
73
+
74
+ <!-- 아이콘만 (ariaLabel 필수) -->
75
+ <UiButton variant="ghost" iconOnly aria-label="삭제">
76
+ <template #icon-left><i class="icon-trashcan size-16" /></template>
77
+ </UiButton>
78
+
79
+ <!-- 링크로 -->
80
+ <UiButton as="a" href="/agent/list" variant="secondary">목록 보기</UiButton>
81
+
82
+ <!-- 외부 ref -->
83
+ <script setup>
84
+ import { ref } from 'vue'
85
+ const btnRef = ref()
86
+ btnRef.value.focus() // defineExpose된 메서드
87
+ </script>
88
+ <UiButton ref="btnRef">포커스 대상</UiButton>
89
+ ```
90
+
91
+ 전체 props는 Storybook 문서를 참고하세요.
92
+
93
+ ## 테마 오버라이드
94
+
95
+ CSS 변수만 덮으면 됩니다:
96
+
97
+ ```css
98
+ /* 소비측 앱의 글로벌 CSS */
99
+ :root {
100
+ --color-primary: #ff7518; /* 오렌지 테마로 */
101
+ --color-primary-hover: #e5660f;
102
+ --color-primary-dark: #c73e07;
103
+ }
104
+ ```
105
+
106
+ ## 개발 환경
107
+
108
+ ```bash
109
+ npm install
110
+ npm run storybook # Storybook (포트 6006)
111
+ npm test # Vitest
112
+ npm run build # 라이브러리 빌드 (dist/)
113
+ npm run build:icons # SVG → base64 inline 재생성 (아이콘 추가 시)
114
+ ```
115
+
116
+ ## 아이콘 추가하기
117
+
118
+ 1. `public/icons/svg/{name}.svg` 에 SVG 추가
119
+ 2. `npm run build:icons` 실행
120
+ 3. `<i class="icon-{name} size-16" />` 로 사용
121
+
122
+ ## 라이센스
123
+
124
+ MIT — 자유롭게 사용·수정·배포 가능.
@@ -0,0 +1,3 @@
1
+ <svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M4.80292 15.157C4.99996 15.3759 5.33718 15.3937 5.55613 15.1966L10.8895 10.3968C11.0018 10.2957 11.066 10.1516 11.066 10.0004C11.066 9.84923 11.0019 9.70515 10.8895 9.604L5.55615 4.80367C5.33722 4.60662 4.99999 4.62436 4.80294 4.84329C4.60589 5.06222 4.62363 5.39945 4.84256 5.5965L9.73544 10.0004L4.84258 14.4038C4.62364 14.6008 4.60588 14.938 4.80292 15.157Z" fill="#000"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M19.5459 5.15741C20.0111 4.68577 20.7708 4.68073 21.2428 5.14569C21.7144 5.61085 21.7195 6.37061 21.2545 6.84256L9.43263 18.8426C9.2072 19.0712 8.89943 19.1999 8.57833 19.2C8.25699 19.2 7.94839 19.0715 7.72286 18.8426L2.74591 13.7894C2.28086 13.3174 2.28574 12.5577 2.75763 12.0926C3.2297 11.6275 3.98937 11.6335 4.4545 12.1055L8.57716 16.289L19.5459 5.15741Z" fill="#5C6677"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
2
+ <path d="M6 9L12 15L18 9" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M1.59961 1.59998L14.3996 14.4" stroke="#000" stroke-width="2" stroke-linecap="round"/>
3
+ <path d="M1.59961 14.4L14.3996 1.60002" stroke="#000" stroke-width="2" stroke-linecap="round"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M10.0003 13.3333L5.83366 9.16667L7.00033 7.95833L9.16699 10.125V3.33333H10.8337V10.125L13.0003 7.95833L14.167 9.16667L10.0003 13.3333ZM5.00033 16.6667C4.54199 16.6667 4.14977 16.5036 3.82366 16.1775C3.49755 15.8514 3.33421 15.4589 3.33366 15V12.5H5.00033V15H15.0003V12.5H16.667V15C16.667 15.4583 16.5039 15.8508 16.1778 16.1775C15.8517 16.5042 15.4592 16.6672 15.0003 16.6667H5.00033Z" fill="#6F7A93"/>
3
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
2
+ <path d="M1.6001 12.5707V4.03599C1.6001 3.55092 1.79221 3.08514 2.13521 2.74215C2.47821 2.39915 2.94399 2.20703 3.42906 2.20703H7.69639C8.0331 2.20703 8.30581 2.47974 8.30581 2.81645C8.30581 3.15315 8.0331 3.42586 7.69639 3.42586H3.42906C3.26737 3.42586 3.11187 3.49014 2.99754 3.60447C2.88321 3.7188 2.81893 3.8743 2.81893 4.03599V12.5707C2.81893 12.7324 2.88321 12.8879 2.99754 13.0022C3.11187 13.1165 3.26737 13.1808 3.42906 13.1808H11.9637C12.1254 13.1808 12.2809 13.1165 12.3953 13.0022C12.5096 12.8879 12.5739 12.7324 12.5739 12.5707V8.30333C12.5739 7.96663 12.8466 7.69391 13.1833 7.69391C13.52 7.69391 13.7927 7.96663 13.7927 8.30333V12.5707C13.7927 13.0557 13.6006 13.5215 13.2576 13.8645C12.9146 14.2075 12.4488 14.3996 11.9637 14.3996H3.42906C2.94399 14.3996 2.47821 14.2075 2.13521 13.8645C1.79221 13.5215 1.6001 13.0557 1.6001 12.5707Z" fill="#000"/>
3
+ <path d="M13.1807 3.50216C13.1807 3.32091 13.1081 3.14737 12.98 3.0192C12.8518 2.89104 12.6783 2.81849 12.497 2.81844C12.3157 2.81844 12.1415 2.89099 12.0133 3.0192L6.51859 8.51465C6.44621 8.58691 6.39309 8.67657 6.36428 8.77471L6.00777 9.99068L7.22517 9.63489H7.22589C7.324 9.60619 7.41363 9.55282 7.48594 9.48057L12.98 3.98583C13.1082 3.85763 13.1807 3.68346 13.1807 3.50216ZM14.3996 3.50216C14.3996 4.00684 14.1992 4.49129 13.8423 4.84816L8.34755 10.3436C8.1576 10.5334 7.92833 10.6784 7.6767 10.7694L7.56739 10.8051L5.8163 11.3174H5.81559C5.65822 11.3633 5.49142 11.3659 5.33263 11.3253C5.17385 11.2846 5.02916 11.2018 4.91325 11.0859C4.79735 10.97 4.71461 10.8253 4.67392 10.6665C4.63324 10.5078 4.63589 10.3409 4.68178 10.1836V10.1829L5.19403 8.43178V8.43106C5.28047 8.13665 5.43983 7.8684 5.65698 7.65161L11.151 2.15687C11.5079 1.8 11.9923 1.59961 12.497 1.59961C13.0016 1.59966 13.4855 1.80005 13.8423 2.15687C14.1991 2.5137 14.3995 2.99753 14.3996 3.50216Z" fill="#000"/>
4
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M2 7.33301H14V8.66634H2V7.33301Z" fill="#8A949E"/>
3
+ <path d="M7.33325 14L7.33325 2L8.66658 2L8.66659 14H7.33325Z" fill="#8A949E"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="20" height="20" viewBox="102 6 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M103.667 16.0001C103.667 20.6026 107.397 24.3334 112 24.3334C116.602 24.3334 120.333 20.6026 120.333 16.0001C120.333 11.3976 116.602 7.66675 112 7.66675V9.33341C113.568 9.33354 115.085 9.88613 116.286 10.8941C117.486 11.9021 118.294 13.301 118.565 14.8449C118.837 16.3889 118.556 17.9792 117.771 19.3365C116.986 20.6937 115.749 21.7311 114.275 22.2663C112.802 22.8014 111.187 22.8002 109.714 22.2628C108.241 21.7254 107.005 20.6861 106.223 19.3277C105.44 17.9693 105.161 16.3785 105.435 14.8349C105.709 13.2914 106.518 11.8937 107.721 10.8876L109.5 12.6667V7.66675H104.5L106.538 9.70591C105.636 10.4875 104.912 11.4542 104.417 12.5402C103.921 13.6263 103.665 14.8063 103.667 16.0001Z" fill="#000"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1.11523C11.866 1.11523 15 4.24924 15 8.11523C15 9.5597 14.5622 10.9018 13.8125 12.0166L18.4229 16.5625C18.6585 16.7952 18.6587 17.1727 18.4229 17.4053L17.4961 18.3184C17.2601 18.551 16.8776 18.551 16.6416 18.3184L12.0684 13.8096C10.9216 14.6304 9.51783 15.1152 8 15.1152C4.13401 15.1152 1 11.9812 1 8.11523C1 4.24924 4.13401 1.11523 8 1.11523ZM8 3.11523C5.23858 3.11523 3 5.35381 3 8.11523C3 10.8767 5.23858 13.1152 8 13.1152C10.7614 13.1152 13 10.8767 13 8.11523C13 5.35381 10.7614 3.11523 8 3.11523Z" fill="#6F7A93"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M4.44443 14.4001C4.05332 14.4001 3.71862 14.261 3.44034 13.9827C3.16206 13.7044 3.02268 13.3695 3.02221 12.9779V3.73343H2.3111V2.31121H5.86665V1.6001H10.1333V2.31121H13.6889V3.73343H12.9778V12.9779C12.9778 13.369 12.8386 13.7039 12.5603 13.9827C12.2821 14.2614 11.9471 14.4006 11.5555 14.4001H4.44443ZM11.5555 3.73343H4.44443V12.9779H11.5555V3.73343ZM5.86665 11.5557H7.28887V5.15565H5.86665V11.5557ZM8.7111 11.5557H10.1333V5.15565H8.7111V11.5557Z" fill="#5C6677"/>
3
+ </svg>
@@ -0,0 +1,242 @@
1
+ import { ComponentOptionsMixin } from 'vue';
2
+ import { ComponentProvideOptions } from 'vue';
3
+ import { DefineComponent } from 'vue';
4
+ import { PublicProps } from 'vue';
5
+ import { Ref } from 'vue';
6
+
7
+ declare const __VLS_component: DefineComponent<Props, {
8
+ focus: () => void | undefined;
9
+ blur: () => void | undefined;
10
+ el: Ref<HTMLButtonElement | HTMLAnchorElement | null, HTMLButtonElement | HTMLAnchorElement | null>;
11
+ }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
12
+ click: (event: MouseEvent) => any;
13
+ }, string, PublicProps, Readonly<Props> & Readonly<{
14
+ onClick?: ((event: MouseEvent) => any) | undefined;
15
+ }>, {
16
+ variant: "primary" | "secondary" | "ghost" | "danger";
17
+ size: Size;
18
+ shape: Shape;
19
+ as: "button" | "a";
20
+ type: "button" | "submit";
21
+ disabled: boolean;
22
+ loading: boolean;
23
+ fullWidth: boolean;
24
+ iconOnly: boolean;
25
+ }, {}, {}, {}, string, ComponentProvideOptions, false, {
26
+ rootEl: unknown;
27
+ }, any>;
28
+
29
+ declare const __VLS_component_2: DefineComponent<Props_2, {
30
+ focus: () => void | undefined;
31
+ blur: () => void | undefined;
32
+ el: Ref<HTMLInputElement | undefined, HTMLInputElement | undefined>;
33
+ }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
34
+ search: (value: string | number) => any;
35
+ "update:modelValue": (value: string | number) => any;
36
+ enter: (value: string | number) => any;
37
+ }, string, PublicProps, Readonly<Props_2> & Readonly<{
38
+ onSearch?: ((value: string | number) => any) | undefined;
39
+ "onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
40
+ onEnter?: ((value: string | number) => any) | undefined;
41
+ }>, {
42
+ size: InputSize;
43
+ shape: "rounded" | "pill";
44
+ type: "text" | "search" | "password" | "email" | "tel";
45
+ disabled: boolean;
46
+ desc: string;
47
+ modelValue: string | number;
48
+ placeholder: string;
49
+ readonly: boolean;
50
+ required: boolean;
51
+ autocomplete: string;
52
+ name: string;
53
+ id: string;
54
+ maxLength: number;
55
+ min: string | number;
56
+ max: string | number;
57
+ step: string | number;
58
+ numberOnly: boolean;
59
+ allowDecimal: boolean;
60
+ allowNegative: boolean;
61
+ decimals: number;
62
+ searchAriaLabel: string;
63
+ }, {}, {}, {}, string, ComponentProvideOptions, false, {
64
+ inputRef: HTMLInputElement;
65
+ }, any>;
66
+
67
+ declare function __VLS_template(): {
68
+ attrs: Partial<{}>;
69
+ slots: {
70
+ 'icon-left'?(_: {}): any;
71
+ default?(_: {}): any;
72
+ 'icon-right'?(_: {}): any;
73
+ };
74
+ refs: {
75
+ rootEl: unknown;
76
+ };
77
+ rootEl: any;
78
+ };
79
+
80
+ declare function __VLS_template_2(): {
81
+ attrs: Partial<{}>;
82
+ slots: {
83
+ 'icon-left'?(_: {}): any;
84
+ 'icon-right'?(_: {}): any;
85
+ };
86
+ refs: {
87
+ inputRef: HTMLInputElement;
88
+ };
89
+ rootEl: any;
90
+ };
91
+
92
+ declare type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
93
+
94
+ declare type __VLS_TemplateResult_2 = ReturnType<typeof __VLS_template_2>;
95
+
96
+ declare type __VLS_WithTemplateSlots<T, S> = T & {
97
+ new (): {
98
+ $slots: S;
99
+ };
100
+ };
101
+
102
+ declare type __VLS_WithTemplateSlots_2<T, S> = T & {
103
+ new (): {
104
+ $slots: S;
105
+ };
106
+ };
107
+
108
+ export declare const INPUT_SIZES: readonly ["sm", "md", "lg", "auth"];
109
+
110
+ export declare type InputSize = (typeof INPUT_SIZES)[number];
111
+
112
+ declare interface Props {
113
+ /**
114
+ * 시멘틱 variant — primary(강조) / secondary(보조) / ghost(트리거) / danger(파괴)
115
+ */
116
+ variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
117
+ /**
118
+ * 사이즈 — xs(24px) / sm(28px) / md(32px·기본) / lg(40px)
119
+ */
120
+ size?: Size;
121
+ /**
122
+ * 아이콘 사이즈 — 미지정 시 size 따라감. 명시 시 override.
123
+ */
124
+ iconSize?: Size;
125
+ /**
126
+ * 모서리 모양 — rounded(기본 6px) / pill(완전 라운드) / circle(iconOnly FAB)
127
+ */
128
+ shape?: Shape;
129
+ /**
130
+ * 렌더링 태그 — button(기본) / a(링크)
131
+ */
132
+ as?: 'button' | 'a';
133
+ /**
134
+ * button 태그일 때만 적용. form 안 의도치 않은 submit 방지로 기본 'button'.
135
+ */
136
+ type?: 'button' | 'submit';
137
+ /**
138
+ * as='a'일 때 링크 경로
139
+ */
140
+ href?: string;
141
+ /**
142
+ * as='a'일 때 link target. '_blank'이면 rel="noopener noreferrer" 자동 부여.
143
+ */
144
+ target?: '_blank' | '_self' | '_parent' | '_top';
145
+ disabled?: boolean;
146
+ loading?: boolean;
147
+ fullWidth?: boolean;
148
+ iconOnly?: boolean;
149
+ /**
150
+ * 접근성 라벨 — iconOnly=true일 때 필수
151
+ */
152
+ ariaLabel?: string;
153
+ }
154
+
155
+ declare interface Props_2 {
156
+ /** v-model 양방향 바인딩 값 */
157
+ modelValue?: string | number;
158
+ /**
159
+ * input HTML type — `search`는 내부적으로 text + 우측 검색 아이콘 자동.
160
+ * `number`는 사용 금지 (한글 IME 깜빡임) → `numberOnly` prop 사용.
161
+ */
162
+ type?: 'text' | 'search' | 'password' | 'email' | 'tel';
163
+ /** 입력 영역 플레이스홀더 텍스트 */
164
+ placeholder?: string;
165
+ /** 비활성화 — 입력 차단 + opacity 0.5 */
166
+ disabled?: boolean;
167
+ /** 읽기 전용 — 표시는 정상, 입력만 차단 */
168
+ readonly?: boolean;
169
+ /** 필수 입력 (HTML required) */
170
+ required?: boolean;
171
+ /** autocomplete HTML 속성 (e.g., "email", "current-password", "off") */
172
+ autocomplete?: string;
173
+ /** form submit 시 사용할 input name 속성 */
174
+ name?: string;
175
+ /** label htmlFor와 연결할 input id 속성 */
176
+ id?: string;
177
+ /** 입력 가능한 최대 글자 수 (HTML 표준 maxlength) */
178
+ maxLength?: number;
179
+ /**
180
+ * 최솟값 — `numberOnly=true` 필수. blur 시점에 자동 보정.
181
+ * type=text 사용으로 HTML native 제약 없음.
182
+ */
183
+ min?: string | number;
184
+ /**
185
+ * 최댓값 — `numberOnly=true` 필수. blur 시점에 자동 보정.
186
+ */
187
+ max?: string | number;
188
+ /**
189
+ * 단위 — `numberOnly=true` 필수. blur 시 step 단위로 반올림.
190
+ * 예: `step=0.1` → 0.05 입력 시 0.1로 보정.
191
+ */
192
+ step?: string | number;
193
+ /**
194
+ * 사이즈 — `sm`(28px) / `md`(32px·기본) / `lg`(40px) / `auth`(44px·로그인 전용)
195
+ * UiButton과 동일 토큰 사용 → 검색바에서 자동 정렬.
196
+ */
197
+ size?: InputSize;
198
+ /**
199
+ * 아이콘 사이즈 — 미지정 시 `size` 따라감, 명시 시 override (xs/sm/md/lg).
200
+ * 슬롯 내 `<i>`에 `size-N` 클래스 안 붙였을 때만 적용.
201
+ */
202
+ iconSize?: Size;
203
+ /**
204
+ * 모서리 모양 — `rounded`(기본 6px) / `pill`(완전 라운드 — 검색바·필터)
205
+ */
206
+ shape?: 'rounded' | 'pill';
207
+ /**
208
+ * 입력 아래 설명 텍스트 — 별도 `<p class="hint">` 사용 금지, 이 prop 사용
209
+ * input의 `aria-describedby`와 자동 연결.
210
+ */
211
+ desc?: string;
212
+ /**
213
+ * 숫자만 허용 — `type="number"` 사용 금지 정책 대신 사용 (한글 IME 깜빡임 방지).
214
+ * `min/max/step`은 이 prop이 true일 때만 동작.
215
+ */
216
+ numberOnly?: boolean;
217
+ /** `numberOnly=true`일 때 소수점 허용 (예: 0.5) */
218
+ allowDecimal?: boolean;
219
+ /** `numberOnly=true`일 때 음수 부호(-) 허용 */
220
+ allowNegative?: boolean;
221
+ /**
222
+ * 소수점 자릿수 제한 — `allowDecimal=true`일 때만 의미.
223
+ * 입력 즉시 초과 자릿수 제거. 예: `decimals=2` → "0.123" 입력 시 "0.12"로 자동 보정.
224
+ */
225
+ decimals?: number;
226
+ /** 검색 버튼 aria-label (type="search"일 때만, 기본 "검색") */
227
+ searchAriaLabel?: string;
228
+ }
229
+
230
+ export declare type Shape = (typeof SHAPES)[number];
231
+
232
+ export declare const SHAPES: readonly ["rounded", "pill", "circle"];
233
+
234
+ export declare type Size = (typeof SIZES)[number];
235
+
236
+ export declare const SIZES: readonly ["xs", "sm", "md", "lg"];
237
+
238
+ export declare const UiButton: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
239
+
240
+ export declare const UiInput: __VLS_WithTemplateSlots_2<typeof __VLS_component_2, __VLS_TemplateResult_2["slots"]>;
241
+
242
+ export { }
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("vue"),K={key:0,class:"ui-button-spinner","aria-hidden":"true"},R={key:1,class:"ui-button-icon"},T={key:2,class:"ui-button-text"},W={key:3,class:"ui-button-icon"},H=t.defineComponent({__name:"UiButton",props:{variant:{default:"primary"},size:{default:"md"},iconSize:{},shape:{default:"rounded"},as:{default:"button"},type:{default:"button"},href:{},target:{},disabled:{type:Boolean,default:!1},loading:{type:Boolean,default:!1},fullWidth:{type:Boolean,default:!1},iconOnly:{type:Boolean,default:!1},ariaLabel:{}},emits:["click"],setup(e,{expose:b,emit:v}){const l=e,c=v,f=o=>{if(l.disabled||l.loading){o.preventDefault(),o.stopPropagation();return}c("click",o)},m=t.ref(null);return b({focus:()=>{var o;return(o=m.value)==null?void 0:o.focus()},blur:()=>{var o;return(o=m.value)==null?void 0:o.blur()},el:m}),(o,y)=>(t.openBlock(),t.createBlock(t.resolveDynamicComponent(e.as),{ref_key:"rootEl",ref:m,class:t.normalizeClass(["ui-button",[`variant-${e.variant}`,`size-${e.size}`,`shape-${e.shape}`,e.iconSize?`icon-size-${e.iconSize}`:null,{"is-disabled":e.disabled,"is-loading":e.loading,"is-full":e.fullWidth,"is-icon-only":e.iconOnly}]]),type:e.as==="button"?e.type:void 0,href:e.as==="a"?e.href:void 0,target:e.as==="a"?e.target:void 0,rel:e.as==="a"&&e.target==="_blank"?"noopener noreferrer":void 0,disabled:e.as==="button"&&(e.disabled||e.loading)?!0:void 0,"aria-disabled":e.as==="a"&&(e.disabled||e.loading)?"true":void 0,tabindex:e.as==="a"&&(e.disabled||e.loading)?-1:void 0,"aria-busy":e.loading||void 0,"aria-label":e.ariaLabel,onClick:f},{default:t.withCtx(()=>[e.loading?(t.openBlock(),t.createElementBlock("span",K)):o.$slots["icon-left"]?(t.openBlock(),t.createElementBlock("span",R,[t.renderSlot(o.$slots,"icon-left",{},void 0,!0)])):t.createCommentVNode("",!0),o.$slots.default&&!e.iconOnly?(t.openBlock(),t.createElementBlock("span",T,[t.renderSlot(o.$slots,"default",{},void 0,!0)])):t.createCommentVNode("",!0),o.$slots["icon-right"]&&!e.loading?(t.openBlock(),t.createElementBlock("span",W,[t.renderSlot(o.$slots,"icon-right",{},void 0,!0)])):t.createCommentVNode("",!0)]),_:3},8,["class","type","href","target","rel","disabled","aria-disabled","tabindex","aria-busy","aria-label"]))}}),C=(e,b)=>{const v=e.__vccOpts||e;for(const[l,c]of b)v[l]=c;return v},j=C(H,[["__scopeId","data-v-a2969a5c"]]),G={key:0,class:"ui-input-icon is-left"},J=["id","type","role","inputmode","value","placeholder","disabled","readonly","required","autocomplete","name","maxlength","aria-describedby"],Q=["disabled","aria-label"],X={key:2,class:"ui-input-icon is-right"},Y=["id"],_=t.defineComponent({inheritAttrs:!1,__name:"UiInput",props:{modelValue:{default:""},type:{default:"text"},placeholder:{default:""},disabled:{type:Boolean,default:!1},readonly:{type:Boolean,default:!1},required:{type:Boolean,default:!1},autocomplete:{default:void 0},name:{default:void 0},id:{default:void 0},maxLength:{default:void 0},min:{default:void 0},max:{default:void 0},step:{default:void 0},size:{default:"md"},iconSize:{},shape:{default:"rounded"},desc:{default:""},numberOnly:{type:Boolean,default:!1},allowDecimal:{type:Boolean,default:!1},allowNegative:{type:Boolean,default:!1},decimals:{default:void 0},searchAriaLabel:{default:"검색"}},emits:["update:modelValue","enter","search"],setup(e,{expose:b,emit:v}){const l=e,c=v,f=t.ref(),m=t.ref(!1),o=t.ref(!1),y=t.useAttrs(),E=t.computed(()=>{const{class:a,style:n,...d}=y;return d}),V=t.computed(()=>y.class),x=t.computed(()=>y.style??void 0),z=t.useId(),N=t.computed(()=>{if(l.desc)return l.id?`${l.id}-desc`:`${z}-desc`}),I=t.computed(()=>{if(l.numberOnly)return l.allowDecimal||l.allowNegative?"decimal":"numeric"}),g=t.computed(()=>{const a=l.decimals;if(a!==void 0&&Number.isInteger(a)&&a>=0)return a}),h=a=>{if(typeof l.modelValue=="number"){if(a===""||a==="-")return a;const n=parseFloat(a);if(!Number.isNaN(n))return n}return a},k=a=>{let n="0-9";l.allowDecimal&&(n+="."),l.allowNegative&&(n+="-");const d=new RegExp(`[^${n}]`,"g");let i=a.replace(d,"");if(l.allowNegative){const s=i.startsWith("-");i=i.replace(/-/g,""),s&&(i="-"+i)}if(l.allowDecimal){const s=i.indexOf(".");if(s!==-1){const r=i.slice(0,s);let u=i.slice(s+1).replace(/\./g,"");g.value!==void 0&&(u=u.slice(0,g.value)),i=u===""&&r===""?"":r+"."+u}}return i},D=a=>{const n=a.trim();if(n==="")return"";const d=k(n);if(d===""||d==="-")return d;let i=parseFloat(d);if(Number.isNaN(i))return d;const s=l.min!==void 0?Number(l.min):void 0,r=l.max!==void 0?Number(l.max):void 0,u=l.step!==void 0?Number(l.step):void 0;if(s!==void 0&&!Number.isNaN(s)&&(i=Math.max(i,s)),r!==void 0&&!Number.isNaN(r)&&(i=Math.min(i,r)),u!==void 0&&u>0&&!Number.isNaN(u)){const S=s!==void 0&&!Number.isNaN(s)?s:0;i=S+Math.round((i-S)/u)*u,s!==void 0&&!Number.isNaN(s)&&(i=Math.max(i,s)),r!==void 0&&!Number.isNaN(r)&&(i=Math.min(i,r));const q=(String(l.step).split(".")[1]||"").length,F=(String(l.min??"").split(".")[1]||"").length,$=Math.max(q,F,l.allowDecimal?2:0),p=g.value,Z=p!==void 0?Math.min($,p):$;i=Number(i.toFixed(Z))}return String(i)},w=()=>{m.value=!0},M=a=>{m.value=!1;const n=a.target;if(!l.numberOnly||l.min===void 0&&l.max===void 0&&l.step===void 0)return;const d=D(n.value);d!==n.value&&(n.value=d,c("update:modelValue",h(d)))},B=a=>{if(l.numberOnly){const n=k(a.value);n!==a.value&&(a.value=n),c("update:modelValue",h(n))}else c("update:modelValue",h(a.value))},O=a=>{o.value||B(a.target)},P=()=>{o.value=!0},U=a=>{o.value=!1,B(a.target)},A=a=>{const n=a.target;c("enter",h(n.value))},L=()=>{var a;l.disabled||c("search",h(((a=f.value)==null?void 0:a.value)??""))};return b({focus:()=>{var a;return(a=f.value)==null?void 0:a.focus()},blur:()=>{var a;return(a=f.value)==null?void 0:a.blur()},el:f}),(a,n)=>(t.openBlock(),t.createElementBlock("div",{class:t.normalizeClass(["ui-input-outer",[V.value,{"has-desc":!!e.desc}]]),style:t.normalizeStyle(x.value)},[t.createElementVNode("div",{class:t.normalizeClass(["ui-input-wrap",[`size-${e.size}`,`shape-${e.shape}`,e.iconSize?`icon-size-${e.iconSize}`:null,{"is-disabled":e.disabled,"is-focused":m.value,"has-icon-left":!!a.$slots["icon-left"],"has-icon-right":!!a.$slots["icon-right"]||e.type==="search"}]])},[a.$slots["icon-left"]?(t.openBlock(),t.createElementBlock("span",G,[t.renderSlot(a.$slots,"icon-left",{},void 0,!0)])):t.createCommentVNode("",!0),t.createElementVNode("input",t.mergeProps(E.value,{id:e.id,ref_key:"inputRef",ref:f,class:"ui-input",type:e.type==="search"?"text":e.type,role:e.type==="search"?"searchbox":void 0,inputmode:I.value,value:e.modelValue,placeholder:e.placeholder,disabled:e.disabled,readonly:e.readonly,required:e.required||void 0,autocomplete:e.autocomplete,name:e.name,maxlength:e.maxLength,"aria-describedby":N.value,onInput:O,onCompositionstart:P,onCompositionend:U,onFocus:w,onBlur:M,onKeydown:t.withKeys(A,["enter"])}),null,16,J),e.type==="search"?(t.openBlock(),t.createElementBlock("button",{key:1,type:"button",class:"ui-input-icon is-right is-search",disabled:e.disabled,"aria-label":e.searchAriaLabel,onClick:L},[...n[0]||(n[0]=[t.createElementVNode("i",{class:"icon-search"},null,-1)])],8,Q)):a.$slots["icon-right"]?(t.openBlock(),t.createElementBlock("span",X,[t.renderSlot(a.$slots,"icon-right",{},void 0,!0)])):t.createCommentVNode("",!0)],2),e.desc?(t.openBlock(),t.createElementBlock("p",{key:0,id:N.value,class:"ui-input-desc"},t.toDisplayString(e.desc),9,Y)):t.createCommentVNode("",!0)],6))}}),ee=C(_,[["__scopeId","data-v-e12a2f24"]]),te=["xs","sm","md","lg"],ae=["sm","md","lg","auth"],le=["rounded","pill","circle"];exports.INPUT_SIZES=ae;exports.SHAPES=le;exports.SIZES=te;exports.UiButton=j;exports.UiInput=ee;
@@ -0,0 +1 @@
1
+ @charset "UTF-8";*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html{-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}body{line-height:1.5;font-family:Pretendard,-apple-system,sans-serif;color:#4d5462}img,svg{display:block;max-width:100%}button,input,select,textarea{font:inherit}button{cursor:pointer}textarea{resize:vertical}a{color:inherit;text-decoration:none}ul,ol{list-style:none}img{height:auto}table{border-collapse:collapse;border-spacing:0}*::-webkit-scrollbar{width:5px;height:5px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-thumb{background:#00000026;border-radius:9999px}*::-webkit-scrollbar-thumb:hover{background:#00000040}.size-8{width:8px;height:8px}.size-10{width:10px;height:10px}.size-12{width:12px;height:12px}.size-14{width:14px;height:14px}.size-16{width:16px;height:16px}.size-20{width:20px;height:20px}.size-24{width:24px;height:24px}.size-28{width:28px;height:28px}.size-32{width:32px;height:32px}.size-36{width:36px;height:36px}.size-40{width:40px;height:40px}.size-48{width:48px;height:48px}.icon-primary{background-color:var(--color-primary)}.icon-danger{background-color:var(--color-danger)}.icon-white{background-color:#fff}.icon-black{background-color:#000}.icon-muted{background-color:#6f7a93}.icon-arrow-right{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxNiAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00LjgwMjkyIDE1LjE1N0M0Ljk5OTk2IDE1LjM3NTkgNS4zMzcxOCAxNS4zOTM3IDUuNTU2MTMgMTUuMTk2NkwxMC44ODk1IDEwLjM5NjhDMTEuMDAxOCAxMC4yOTU3IDExLjA2NiAxMC4xNTE2IDExLjA2NiAxMC4wMDA0QzExLjA2NiA5Ljg0OTIzIDExLjAwMTkgOS43MDUxNSAxMC44ODk1IDkuNjA0TDUuNTU2MTUgNC44MDM2N0M1LjMzNzIyIDQuNjA2NjIgNC45OTk5OSA0LjYyNDM2IDQuODAyOTQgNC44NDMyOUM0LjYwNTg5IDUuMDYyMjIgNC42MjM2MyA1LjM5OTQ1IDQuODQyNTYgNS41OTY1TDkuNzM1NDQgMTAuMDAwNEw0Ljg0MjU4IDE0LjQwMzhDNC42MjM2NCAxNC42MDA4IDQuNjA1ODggMTQuOTM4IDQuODAyOTIgMTUuMTU3WiIgZmlsbD0iIzAwMCIvPgo8L3N2Zz4K);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxNiAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00LjgwMjkyIDE1LjE1N0M0Ljk5OTk2IDE1LjM3NTkgNS4zMzcxOCAxNS4zOTM3IDUuNTU2MTMgMTUuMTk2NkwxMC44ODk1IDEwLjM5NjhDMTEuMDAxOCAxMC4yOTU3IDExLjA2NiAxMC4xNTE2IDExLjA2NiAxMC4wMDA0QzExLjA2NiA5Ljg0OTIzIDExLjAwMTkgOS43MDUxNSAxMC44ODk1IDkuNjA0TDUuNTU2MTUgNC44MDM2N0M1LjMzNzIyIDQuNjA2NjIgNC45OTk5OSA0LjYyNDM2IDQuODAyOTQgNC44NDMyOUM0LjYwNTg5IDUuMDYyMjIgNC42MjM2MyA1LjM5OTQ1IDQuODQyNTYgNS41OTY1TDkuNzM1NDQgMTAuMDAwNEw0Ljg0MjU4IDE0LjQwMzhDNC42MjM2NCAxNC42MDA4IDQuNjA1ODggMTQuOTM4IDQuODAyOTIgMTUuMTU3WiIgZmlsbD0iIzAwMCIvPgo8L3N2Zz4K);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}.icon-check{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE5LjU0NTkgNS4xNTc0MUMyMC4wMTExIDQuNjg1NzcgMjAuNzcwOCA0LjY4MDczIDIxLjI0MjggNS4xNDU2OUMyMS43MTQ0IDUuNjEwODUgMjEuNzE5NSA2LjM3MDYxIDIxLjI1NDUgNi44NDI1Nkw5LjQzMjYzIDE4Ljg0MjZDOS4yMDcyIDE5LjA3MTIgOC44OTk0MyAxOS4xOTk5IDguNTc4MzMgMTkuMkM4LjI1Njk5IDE5LjIgNy45NDgzOSAxOS4wNzE1IDcuNzIyODYgMTguODQyNkwyLjc0NTkxIDEzLjc4OTRDMi4yODA4NiAxMy4zMTc0IDIuMjg1NzQgMTIuNTU3NyAyLjc1NzYzIDEyLjA5MjZDMy4yMjk3IDExLjYyNzUgMy45ODkzNyAxMS42MzM1IDQuNDU0NSAxMi4xMDU1TDguNTc3MTYgMTYuMjg5TDE5LjU0NTkgNS4xNTc0MVoiIGZpbGw9IiM1QzY2NzciLz4KPC9zdmc+Cg==);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE5LjU0NTkgNS4xNTc0MUMyMC4wMTExIDQuNjg1NzcgMjAuNzcwOCA0LjY4MDczIDIxLjI0MjggNS4xNDU2OUMyMS43MTQ0IDUuNjEwODUgMjEuNzE5NSA2LjM3MDYxIDIxLjI1NDUgNi44NDI1Nkw5LjQzMjYzIDE4Ljg0MjZDOS4yMDcyIDE5LjA3MTIgOC44OTk0MyAxOS4xOTk5IDguNTc4MzMgMTkuMkM4LjI1Njk5IDE5LjIgNy45NDgzOSAxOS4wNzE1IDcuNzIyODYgMTguODQyNkwyLjc0NTkxIDEzLjc4OTRDMi4yODA4NiAxMy4zMTc0IDIuMjg1NzQgMTIuNTU3NyAyLjc1NzYzIDEyLjA5MjZDMy4yMjk3IDExLjYyNzUgMy45ODkzNyAxMS42MzM1IDQuNDU0NSAxMi4xMDU1TDguNTc3MTYgMTYuMjg5TDE5LjU0NTkgNS4xNTc0MVoiIGZpbGw9IiM1QzY2NzciLz4KPC9zdmc+Cg==);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}.icon-chevron-down{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIj4NCiAgPHBhdGggZD0iTTYgOUwxMiAxNUwxOCA5IiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+DQo8L3N2Zz4NCg==);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIj4NCiAgPHBhdGggZD0iTTYgOUwxMiAxNUwxOCA5IiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+DQo8L3N2Zz4NCg==);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}.icon-close{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEuNTk5NjEgMS41OTk5OEwxNC4zOTk2IDE0LjQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KPHBhdGggZD0iTTEuNTk5NjEgMTQuNEwxNC4zOTk2IDEuNjAwMDIiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KPC9zdmc+Cg==);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEuNTk5NjEgMS41OTk5OEwxNC4zOTk2IDE0LjQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KPHBhdGggZD0iTTEuNTk5NjEgMTQuNEwxNC4zOTk2IDEuNjAwMDIiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KPC9zdmc+Cg==);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}.icon-download{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik0xMC4wMDAzIDEzLjMzMzNMNS44MzM2NiA5LjE2NjY3TDcuMDAwMzMgNy45NTgzM0w5LjE2Njk5IDEwLjEyNVYzLjMzMzMzSDEwLjgzMzdWMTAuMTI1TDEzLjAwMDMgNy45NTgzM0wxNC4xNjcgOS4xNjY2N0wxMC4wMDAzIDEzLjMzMzNaTTUuMDAwMzMgMTYuNjY2N0M0LjU0MTk5IDE2LjY2NjcgNC4xNDk3NyAxNi41MDM2IDMuODIzNjYgMTYuMTc3NUMzLjQ5NzU1IDE1Ljg1MTQgMy4zMzQyMSAxNS40NTg5IDMuMzMzNjYgMTVWMTIuNUg1LjAwMDMzVjE1SDE1LjAwMDNWMTIuNUgxNi42NjdWMTVDMTYuNjY3IDE1LjQ1ODMgMTYuNTAzOSAxNS44NTA4IDE2LjE3NzggMTYuMTc3NUMxNS44NTE3IDE2LjUwNDIgMTUuNDU5MiAxNi42NjcyIDE1LjAwMDMgMTYuNjY2N0g1LjAwMDMzWiIgZmlsbD0iIzZGN0E5MyIvPg0KPC9zdmc+DQo=);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik0xMC4wMDAzIDEzLjMzMzNMNS44MzM2NiA5LjE2NjY3TDcuMDAwMzMgNy45NTgzM0w5LjE2Njk5IDEwLjEyNVYzLjMzMzMzSDEwLjgzMzdWMTAuMTI1TDEzLjAwMDMgNy45NTgzM0wxNC4xNjcgOS4xNjY2N0wxMC4wMDAzIDEzLjMzMzNaTTUuMDAwMzMgMTYuNjY2N0M0LjU0MTk5IDE2LjY2NjcgNC4xNDk3NyAxNi41MDM2IDMuODIzNjYgMTYuMTc3NUMzLjQ5NzU1IDE1Ljg1MTQgMy4zMzQyMSAxNS40NTg5IDMuMzMzNjYgMTVWMTIuNUg1LjAwMDMzVjE1SDE1LjAwMDNWMTIuNUgxNi42NjdWMTVDMTYuNjY3IDE1LjQ1ODMgMTYuNTAzOSAxNS44NTA4IDE2LjE3NzggMTYuMTc3NUMxNS44NTE3IDE2LjUwNDIgMTUuNDU5MiAxNi42NjcyIDE1LjAwMDMgMTYuNjY2N0g1LjAwMDMzWiIgZmlsbD0iIzZGN0E5MyIvPg0KPC9zdmc+DQo=);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}.icon-edit{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2IiBmaWxsPSJub25lIj4NCiAgPHBhdGggZD0iTTEuNjAwMSAxMi41NzA3VjQuMDM1OTlDMS42MDAxIDMuNTUwOTIgMS43OTIyMSAzLjA4NTE0IDIuMTM1MjEgMi43NDIxNUMyLjQ3ODIxIDIuMzk5MTUgMi45NDM5OSAyLjIwNzAzIDMuNDI5MDYgMi4yMDcwM0g3LjY5NjM5QzguMDMzMSAyLjIwNzAzIDguMzA1ODEgMi40Nzk3NCA4LjMwNTgxIDIuODE2NDVDOC4zMDU4MSAzLjE1MzE1IDguMDMzMSAzLjQyNTg2IDcuNjk2MzkgMy40MjU4NkgzLjQyOTA2QzMuMjY3MzcgMy40MjU4NiAzLjExMTg3IDMuNDkwMTQgMi45OTc1NCAzLjYwNDQ3QzIuODgzMjEgMy43MTg4IDIuODE4OTMgMy44NzQzIDIuODE4OTMgNC4wMzU5OVYxMi41NzA3QzIuODE4OTMgMTIuNzMyNCAyLjg4MzIxIDEyLjg4NzkgMi45OTc1NCAxMy4wMDIyQzMuMTExODcgMTMuMTE2NSAzLjI2NzM3IDEzLjE4MDggMy40MjkwNiAxMy4xODA4SDExLjk2MzdDMTIuMTI1NCAxMy4xODA4IDEyLjI4MDkgMTMuMTE2NSAxMi4zOTUzIDEzLjAwMjJDMTIuNTA5NiAxMi44ODc5IDEyLjU3MzkgMTIuNzMyNCAxMi41NzM5IDEyLjU3MDdWOC4zMDMzM0MxMi41NzM5IDcuOTY2NjMgMTIuODQ2NiA3LjY5MzkxIDEzLjE4MzMgNy42OTM5MUMxMy41MiA3LjY5MzkxIDEzLjc5MjcgNy45NjY2MyAxMy43OTI3IDguMzAzMzNWMTIuNTcwN0MxMy43OTI3IDEzLjA1NTcgMTMuNjAwNiAxMy41MjE1IDEzLjI1NzYgMTMuODY0NUMxMi45MTQ2IDE0LjIwNzUgMTIuNDQ4OCAxNC4zOTk2IDExLjk2MzcgMTQuMzk5NkgzLjQyOTA2QzIuOTQzOTkgMTQuMzk5NiAyLjQ3ODIxIDE0LjIwNzUgMi4xMzUyMSAxMy44NjQ1QzEuNzkyMjEgMTMuNTIxNSAxLjYwMDEgMTMuMDU1NyAxLjYwMDEgMTIuNTcwN1oiIGZpbGw9IiMwMDAiLz4NCiAgPHBhdGggZD0iTTEzLjE4MDcgMy41MDIxNkMxMy4xODA3IDMuMzIwOTEgMTMuMTA4MSAzLjE0NzM3IDEyLjk4IDMuMDE5MkMxMi44NTE4IDIuODkxMDQgMTIuNjc4MyAyLjgxODQ5IDEyLjQ5NyAyLjgxODQ0QzEyLjMxNTcgMi44MTg0NCAxMi4xNDE1IDIuODkwOTkgMTIuMDEzMyAzLjAxOTJMNi41MTg1OSA4LjUxNDY1QzYuNDQ2MjEgOC41ODY5MSA2LjM5MzA5IDguNjc2NTcgNi4zNjQyOCA4Ljc3NDcxTDYuMDA3NzcgOS45OTA2OEw3LjIyNTE3IDkuNjM0ODlINy4yMjU4OUM3LjMyNCA5LjYwNjE5IDcuNDEzNjMgOS41NTI4MiA3LjQ4NTk0IDkuNDgwNTdMMTIuOTggMy45ODU4M0MxMy4xMDgyIDMuODU3NjMgMTMuMTgwNyAzLjY4MzQ2IDEzLjE4MDcgMy41MDIxNlpNMTQuMzk5NiAzLjUwMjE2QzE0LjM5OTYgNC4wMDY4NCAxNC4xOTkyIDQuNDkxMjkgMTMuODQyMyA0Ljg0ODE2TDguMzQ3NTUgMTAuMzQzNkM4LjE1NzYgMTAuNTMzNCA3LjkyODMzIDEwLjY3ODQgNy42NzY3IDEwLjc2OTRMNy41NjczOSAxMC44MDUxTDUuODE2MyAxMS4zMTc0SDUuODE1NTlDNS42NTgyMiAxMS4zNjMzIDUuNDkxNDIgMTEuMzY1OSA1LjMzMjYzIDExLjMyNTNDNS4xNzM4NSAxMS4yODQ2IDUuMDI5MTYgMTEuMjAxOCA0LjkxMzI1IDExLjA4NTlDNC43OTczNSAxMC45NyA0LjcxNDYxIDEwLjgyNTMgNC42NzM5MiAxMC42NjY1QzQuNjMzMjQgMTAuNTA3OCA0LjYzNTg5IDEwLjM0MDkgNC42ODE3OCAxMC4xODM2VjEwLjE4MjlMNS4xOTQwMyA4LjQzMTc4VjguNDMxMDZDNS4yODA0NyA4LjEzNjY1IDUuNDM5ODMgNy44Njg0IDUuNjU2OTggNy42NTE2MUwxMS4xNTEgMi4xNTY4N0MxMS41MDc5IDEuOCAxMS45OTIzIDEuNTk5NjEgMTIuNDk3IDEuNTk5NjFDMTMuMDAxNiAxLjU5OTY2IDEzLjQ4NTUgMS44MDAwNSAxMy44NDIzIDIuMTU2ODdDMTQuMTk5MSAyLjUxMzcgMTQuMzk5NSAyLjk5NzUzIDE0LjM5OTYgMy41MDIxNloiIGZpbGw9IiMwMDAiLz4NCjwvc3ZnPg0K);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2IiBmaWxsPSJub25lIj4NCiAgPHBhdGggZD0iTTEuNjAwMSAxMi41NzA3VjQuMDM1OTlDMS42MDAxIDMuNTUwOTIgMS43OTIyMSAzLjA4NTE0IDIuMTM1MjEgMi43NDIxNUMyLjQ3ODIxIDIuMzk5MTUgMi45NDM5OSAyLjIwNzAzIDMuNDI5MDYgMi4yMDcwM0g3LjY5NjM5QzguMDMzMSAyLjIwNzAzIDguMzA1ODEgMi40Nzk3NCA4LjMwNTgxIDIuODE2NDVDOC4zMDU4MSAzLjE1MzE1IDguMDMzMSAzLjQyNTg2IDcuNjk2MzkgMy40MjU4NkgzLjQyOTA2QzMuMjY3MzcgMy40MjU4NiAzLjExMTg3IDMuNDkwMTQgMi45OTc1NCAzLjYwNDQ3QzIuODgzMjEgMy43MTg4IDIuODE4OTMgMy44NzQzIDIuODE4OTMgNC4wMzU5OVYxMi41NzA3QzIuODE4OTMgMTIuNzMyNCAyLjg4MzIxIDEyLjg4NzkgMi45OTc1NCAxMy4wMDIyQzMuMTExODcgMTMuMTE2NSAzLjI2NzM3IDEzLjE4MDggMy40MjkwNiAxMy4xODA4SDExLjk2MzdDMTIuMTI1NCAxMy4xODA4IDEyLjI4MDkgMTMuMTE2NSAxMi4zOTUzIDEzLjAwMjJDMTIuNTA5NiAxMi44ODc5IDEyLjU3MzkgMTIuNzMyNCAxMi41NzM5IDEyLjU3MDdWOC4zMDMzM0MxMi41NzM5IDcuOTY2NjMgMTIuODQ2NiA3LjY5MzkxIDEzLjE4MzMgNy42OTM5MUMxMy41MiA3LjY5MzkxIDEzLjc5MjcgNy45NjY2MyAxMy43OTI3IDguMzAzMzNWMTIuNTcwN0MxMy43OTI3IDEzLjA1NTcgMTMuNjAwNiAxMy41MjE1IDEzLjI1NzYgMTMuODY0NUMxMi45MTQ2IDE0LjIwNzUgMTIuNDQ4OCAxNC4zOTk2IDExLjk2MzcgMTQuMzk5NkgzLjQyOTA2QzIuOTQzOTkgMTQuMzk5NiAyLjQ3ODIxIDE0LjIwNzUgMi4xMzUyMSAxMy44NjQ1QzEuNzkyMjEgMTMuNTIxNSAxLjYwMDEgMTMuMDU1NyAxLjYwMDEgMTIuNTcwN1oiIGZpbGw9IiMwMDAiLz4NCiAgPHBhdGggZD0iTTEzLjE4MDcgMy41MDIxNkMxMy4xODA3IDMuMzIwOTEgMTMuMTA4MSAzLjE0NzM3IDEyLjk4IDMuMDE5MkMxMi44NTE4IDIuODkxMDQgMTIuNjc4MyAyLjgxODQ5IDEyLjQ5NyAyLjgxODQ0QzEyLjMxNTcgMi44MTg0NCAxMi4xNDE1IDIuODkwOTkgMTIuMDEzMyAzLjAxOTJMNi41MTg1OSA4LjUxNDY1QzYuNDQ2MjEgOC41ODY5MSA2LjM5MzA5IDguNjc2NTcgNi4zNjQyOCA4Ljc3NDcxTDYuMDA3NzcgOS45OTA2OEw3LjIyNTE3IDkuNjM0ODlINy4yMjU4OUM3LjMyNCA5LjYwNjE5IDcuNDEzNjMgOS41NTI4MiA3LjQ4NTk0IDkuNDgwNTdMMTIuOTggMy45ODU4M0MxMy4xMDgyIDMuODU3NjMgMTMuMTgwNyAzLjY4MzQ2IDEzLjE4MDcgMy41MDIxNlpNMTQuMzk5NiAzLjUwMjE2QzE0LjM5OTYgNC4wMDY4NCAxNC4xOTkyIDQuNDkxMjkgMTMuODQyMyA0Ljg0ODE2TDguMzQ3NTUgMTAuMzQzNkM4LjE1NzYgMTAuNTMzNCA3LjkyODMzIDEwLjY3ODQgNy42NzY3IDEwLjc2OTRMNy41NjczOSAxMC44MDUxTDUuODE2MyAxMS4zMTc0SDUuODE1NTlDNS42NTgyMiAxMS4zNjMzIDUuNDkxNDIgMTEuMzY1OSA1LjMzMjYzIDExLjMyNTNDNS4xNzM4NSAxMS4yODQ2IDUuMDI5MTYgMTEuMjAxOCA0LjkxMzI1IDExLjA4NTlDNC43OTczNSAxMC45NyA0LjcxNDYxIDEwLjgyNTMgNC42NzM5MiAxMC42NjY1QzQuNjMzMjQgMTAuNTA3OCA0LjYzNTg5IDEwLjM0MDkgNC42ODE3OCAxMC4xODM2VjEwLjE4MjlMNS4xOTQwMyA4LjQzMTc4VjguNDMxMDZDNS4yODA0NyA4LjEzNjY1IDUuNDM5ODMgNy44Njg0IDUuNjU2OTggNy42NTE2MUwxMS4xNTEgMi4xNTY4N0MxMS41MDc5IDEuOCAxMS45OTIzIDEuNTk5NjEgMTIuNDk3IDEuNTk5NjFDMTMuMDAxNiAxLjU5OTY2IDEzLjQ4NTUgMS44MDAwNSAxMy44NDIzIDIuMTU2ODdDMTQuMTk5MSAyLjUxMzcgMTQuMzk5NSAyLjk5NzUzIDE0LjM5OTYgMy41MDIxNloiIGZpbGw9IiMwMDAiLz4NCjwvc3ZnPg0K);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}.icon-plus{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik0yIDcuMzMzMDFIMTRWOC42NjYzNEgyVjcuMzMzMDFaIiBmaWxsPSIjOEE5NDlFIi8+DQo8cGF0aCBkPSJNNy4zMzMyNSAxNEw3LjMzMzI1IDJMOC42NjY1OCAyTDguNjY2NTkgMTRINy4zMzMyNVoiIGZpbGw9IiM4QTk0OUUiLz4NCjwvc3ZnPg0K);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik0yIDcuMzMzMDFIMTRWOC42NjYzNEgyVjcuMzMzMDFaIiBmaWxsPSIjOEE5NDlFIi8+DQo8cGF0aCBkPSJNNy4zMzMyNSAxNEw3LjMzMzI1IDJMOC42NjY1OCAyTDguNjY2NTkgMTRINy4zMzMyNVoiIGZpbGw9IiM4QTk0OUUiLz4NCjwvc3ZnPg0K);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}.icon-refresh{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjEwMiA2IDIwIDIwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KPHBhdGggZD0iTTEwMy42NjcgMTYuMDAwMUMxMDMuNjY3IDIwLjYwMjYgMTA3LjM5NyAyNC4zMzM0IDExMiAyNC4zMzM0QzExNi42MDIgMjQuMzMzNCAxMjAuMzMzIDIwLjYwMjYgMTIwLjMzMyAxNi4wMDAxQzEyMC4zMzMgMTEuMzk3NiAxMTYuNjAyIDcuNjY2NzUgMTEyIDcuNjY2NzVWOS4zMzM0MUMxMTMuNTY4IDkuMzMzNTQgMTE1LjA4NSA5Ljg4NjEzIDExNi4yODYgMTAuODk0MUMxMTcuNDg2IDExLjkwMjEgMTE4LjI5NCAxMy4zMDEgMTE4LjU2NSAxNC44NDQ5QzExOC44MzcgMTYuMzg4OSAxMTguNTU2IDE3Ljk3OTIgMTE3Ljc3MSAxOS4zMzY1QzExNi45ODYgMjAuNjkzNyAxMTUuNzQ5IDIxLjczMTEgMTE0LjI3NSAyMi4yNjYzQzExMi44MDIgMjIuODAxNCAxMTEuMTg3IDIyLjgwMDIgMTA5LjcxNCAyMi4yNjI4QzEwOC4yNDEgMjEuNzI1NCAxMDcuMDA1IDIwLjY4NjEgMTA2LjIyMyAxOS4zMjc3QzEwNS40NCAxNy45NjkzIDEwNS4xNjEgMTYuMzc4NSAxMDUuNDM1IDE0LjgzNDlDMTA1LjcwOSAxMy4yOTE0IDEwNi41MTggMTEuODkzNyAxMDcuNzIxIDEwLjg4NzZMMTA5LjUgMTIuNjY2N1Y3LjY2Njc1SDEwNC41TDEwNi41MzggOS43MDU5MUMxMDUuNjM2IDEwLjQ4NzUgMTA0LjkxMiAxMS40NTQyIDEwNC40MTcgMTIuNTQwMkMxMDMuOTIxIDEzLjYyNjMgMTAzLjY2NSAxNC44MDYzIDEwMy42NjcgMTYuMDAwMVoiIGZpbGw9IiMwMDAiLz4NCjwvc3ZnPg0K);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjEwMiA2IDIwIDIwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KPHBhdGggZD0iTTEwMy42NjcgMTYuMDAwMUMxMDMuNjY3IDIwLjYwMjYgMTA3LjM5NyAyNC4zMzM0IDExMiAyNC4zMzM0QzExNi42MDIgMjQuMzMzNCAxMjAuMzMzIDIwLjYwMjYgMTIwLjMzMyAxNi4wMDAxQzEyMC4zMzMgMTEuMzk3NiAxMTYuNjAyIDcuNjY2NzUgMTEyIDcuNjY2NzVWOS4zMzM0MUMxMTMuNTY4IDkuMzMzNTQgMTE1LjA4NSA5Ljg4NjEzIDExNi4yODYgMTAuODk0MUMxMTcuNDg2IDExLjkwMjEgMTE4LjI5NCAxMy4zMDEgMTE4LjU2NSAxNC44NDQ5QzExOC44MzcgMTYuMzg4OSAxMTguNTU2IDE3Ljk3OTIgMTE3Ljc3MSAxOS4zMzY1QzExNi45ODYgMjAuNjkzNyAxMTUuNzQ5IDIxLjczMTEgMTE0LjI3NSAyMi4yNjYzQzExMi44MDIgMjIuODAxNCAxMTEuMTg3IDIyLjgwMDIgMTA5LjcxNCAyMi4yNjI4QzEwOC4yNDEgMjEuNzI1NCAxMDcuMDA1IDIwLjY4NjEgMTA2LjIyMyAxOS4zMjc3QzEwNS40NCAxNy45NjkzIDEwNS4xNjEgMTYuMzc4NSAxMDUuNDM1IDE0LjgzNDlDMTA1LjcwOSAxMy4yOTE0IDEwNi41MTggMTEuODkzNyAxMDcuNzIxIDEwLjg4NzZMMTA5LjUgMTIuNjY2N1Y3LjY2Njc1SDEwNC41TDEwNi41MzggOS43MDU5MUMxMDUuNjM2IDEwLjQ4NzUgMTA0LjkxMiAxMS40NTQyIDEwNC40MTcgMTIuNTQwMkMxMDMuOTIxIDEzLjYyNjMgMTAzLjY2NSAxNC44MDYzIDEwMy42NjcgMTYuMDAwMVoiIGZpbGw9IiMwMDAiLz4NCjwvc3ZnPg0K);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}.icon-search{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOCAxLjExNTIzQzExLjg2NiAxLjExNTIzIDE1IDQuMjQ5MjQgMTUgOC4xMTUyM0MxNSA5LjU1OTcgMTQuNTYyMiAxMC45MDE4IDEzLjgxMjUgMTIuMDE2NkwxOC40MjI5IDE2LjU2MjVDMTguNjU4NSAxNi43OTUyIDE4LjY1ODcgMTcuMTcyNyAxOC40MjI5IDE3LjQwNTNMMTcuNDk2MSAxOC4zMTg0QzE3LjI2MDEgMTguNTUxIDE2Ljg3NzYgMTguNTUxIDE2LjY0MTYgMTguMzE4NEwxMi4wNjg0IDEzLjgwOTZDMTAuOTIxNiAxNC42MzA0IDkuNTE3ODMgMTUuMTE1MiA4IDE1LjExNTJDNC4xMzQwMSAxNS4xMTUyIDEgMTEuOTgxMiAxIDguMTE1MjNDMSA0LjI0OTI0IDQuMTM0MDEgMS4xMTUyMyA4IDEuMTE1MjNaTTggMy4xMTUyM0M1LjIzODU4IDMuMTE1MjMgMyA1LjM1MzgxIDMgOC4xMTUyM0MzIDEwLjg3NjcgNS4yMzg1OCAxMy4xMTUyIDggMTMuMTE1MkMxMC43NjE0IDEzLjExNTIgMTMgMTAuODc2NyAxMyA4LjExNTIzQzEzIDUuMzUzODEgMTAuNzYxNCAzLjExNTIzIDggMy4xMTUyM1oiIGZpbGw9IiM2RjdBOTMiLz4NCjwvc3ZnPg0K);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOCAxLjExNTIzQzExLjg2NiAxLjExNTIzIDE1IDQuMjQ5MjQgMTUgOC4xMTUyM0MxNSA5LjU1OTcgMTQuNTYyMiAxMC45MDE4IDEzLjgxMjUgMTIuMDE2NkwxOC40MjI5IDE2LjU2MjVDMTguNjU4NSAxNi43OTUyIDE4LjY1ODcgMTcuMTcyNyAxOC40MjI5IDE3LjQwNTNMMTcuNDk2MSAxOC4zMTg0QzE3LjI2MDEgMTguNTUxIDE2Ljg3NzYgMTguNTUxIDE2LjY0MTYgMTguMzE4NEwxMi4wNjg0IDEzLjgwOTZDMTAuOTIxNiAxNC42MzA0IDkuNTE3ODMgMTUuMTE1MiA4IDE1LjExNTJDNC4xMzQwMSAxNS4xMTUyIDEgMTEuOTgxMiAxIDguMTE1MjNDMSA0LjI0OTI0IDQuMTM0MDEgMS4xMTUyMyA4IDEuMTE1MjNaTTggMy4xMTUyM0M1LjIzODU4IDMuMTE1MjMgMyA1LjM1MzgxIDMgOC4xMTUyM0MzIDEwLjg3NjcgNS4yMzg1OCAxMy4xMTUyIDggMTMuMTE1MkMxMC43NjE0IDEzLjExNTIgMTMgMTAuODc2NyAxMyA4LjExNTIzQzEzIDUuMzUzODEgMTAuNzYxNCAzLjExNTIzIDggMy4xMTUyM1oiIGZpbGw9IiM2RjdBOTMiLz4NCjwvc3ZnPg0K);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}.icon-trashcan{display:inline-block;vertical-align:middle;flex-shrink:0;mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik00LjQ0NDQzIDE0LjQwMDFDNC4wNTMzMiAxNC40MDAxIDMuNzE4NjIgMTQuMjYxIDMuNDQwMzQgMTMuOTgyN0MzLjE2MjA2IDEzLjcwNDQgMy4wMjI2OCAxMy4zNjk1IDMuMDIyMjEgMTIuOTc3OVYzLjczMzQzSDIuMzExMVYyLjMxMTIxSDUuODY2NjVWMS42MDAxSDEwLjEzMzNWMi4zMTEyMUgxMy42ODg5VjMuNzMzNDNIMTIuOTc3OFYxMi45Nzc5QzEyLjk3NzggMTMuMzY5IDEyLjgzODYgMTMuNzAzOSAxMi41NjAzIDEzLjk4MjdDMTIuMjgyMSAxNC4yNjE0IDExLjk0NzEgMTQuNDAwNiAxMS41NTU1IDE0LjQwMDFINC40NDQ0M1pNMTEuNTU1NSAzLjczMzQzSDQuNDQ0NDNWMTIuOTc3OUgxMS41NTU1VjMuNzMzNDNaTTUuODY2NjUgMTEuNTU1N0g3LjI4ODg3VjUuMTU1NjVINS44NjY2NVYxMS41NTU3Wk04LjcxMTEgMTEuNTU1N0gxMC4xMzMzVjUuMTU1NjVIOC43MTExVjExLjU1NTdaIiBmaWxsPSIjNUM2Njc3Ii8+DQo8L3N2Zz4NCg==);mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik00LjQ0NDQzIDE0LjQwMDFDNC4wNTMzMiAxNC40MDAxIDMuNzE4NjIgMTQuMjYxIDMuNDQwMzQgMTMuOTgyN0MzLjE2MjA2IDEzLjcwNDQgMy4wMjI2OCAxMy4zNjk1IDMuMDIyMjEgMTIuOTc3OVYzLjczMzQzSDIuMzExMVYyLjMxMTIxSDUuODY2NjVWMS42MDAxSDEwLjEzMzNWMi4zMTEyMUgxMy42ODg5VjMuNzMzNDNIMTIuOTc3OFYxMi45Nzc5QzEyLjk3NzggMTMuMzY5IDEyLjgzODYgMTMuNzAzOSAxMi41NjAzIDEzLjk4MjdDMTIuMjgyMSAxNC4yNjE0IDExLjk0NzEgMTQuNDAwNiAxMS41NTU1IDE0LjQwMDFINC40NDQ0M1pNMTEuNTU1NSAzLjczMzQzSDQuNDQ0NDNWMTIuOTc3OUgxMS41NTU1VjMuNzMzNDNaTTUuODY2NjUgMTEuNTU1N0g3LjI4ODg3VjUuMTU1NjVINS44NjY2NVYxMS41NTU3Wk04LjcxMTEgMTEuNTU1N0gxMC4xMzMzVjUuMTU1NjVIOC43MTExVjExLjU1NTdaIiBmaWxsPSIjNUM2Njc3Ii8+DQo8L3N2Zz4NCg==);-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain;background-color:currentColor}:root{--color-primary: #3c69db;--color-primary-hover: #1d4ed8;--color-primary-dark: #2b43a2;--color-primary-dark-hover: #1d3589;--color-primary-rgb: 60, 105, 219;--color-primary-bg: #dee9fb;--color-danger: #dc2626;--color-danger-hover: #b91c1c;--color-danger-dark: #991b1b;--color-border: #dce4e9;--color-border-light: #ecf0f3;--color-text-primary: #4d5462;--color-text-secondary: #64748b;--color-text-heading-sub: #2d3139;--color-background: #f4f7f9}.ui-button[data-v-a2969a5c]{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:1px solid transparent;cursor:pointer;transition:background-color .2s ease,border-color .2s ease,color .2s ease;white-space:nowrap;letter-spacing:-.02em;text-decoration:none;font-weight:700;line-height:1.5}.ui-button[data-v-a2969a5c]:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ui-button.size-xs[data-v-a2969a5c]{height:24px;padding:0 8px;font-size:12px}.ui-button.size-xs .ui-button-icon[data-v-a2969a5c] i:not([class*=size-]){width:12px;height:12px}.ui-button.size-xs .ui-button-spinner[data-v-a2969a5c]{width:12px;height:12px;border-width:1.5px}.ui-button.size-sm[data-v-a2969a5c]{height:28px;padding:0 10px;font-size:13px}.ui-button.size-sm .ui-button-icon[data-v-a2969a5c] i:not([class*=size-]){width:16px;height:16px}.ui-button.size-sm .ui-button-spinner[data-v-a2969a5c]{width:16px;height:16px;border-width:1.5px}.ui-button.size-md[data-v-a2969a5c]{height:32px;padding:0 12px;font-size:14px}.ui-button.size-md .ui-button-icon[data-v-a2969a5c] i:not([class*=size-]){width:18px;height:18px}.ui-button.size-md .ui-button-spinner[data-v-a2969a5c]{width:18px;height:18px;border-width:1.5px}.ui-button.size-lg[data-v-a2969a5c]{height:40px;padding:0 16px;font-size:15px}.ui-button.size-lg .ui-button-icon[data-v-a2969a5c] i:not([class*=size-]){width:20px;height:20px}.ui-button.size-lg .ui-button-spinner[data-v-a2969a5c]{width:20px;height:20px;border-width:2px}.ui-button.icon-size-xs .ui-button-icon[data-v-a2969a5c] i:not([class*=size-]){width:12px;height:12px}.ui-button.icon-size-sm .ui-button-icon[data-v-a2969a5c] i:not([class*=size-]){width:16px;height:16px}.ui-button.icon-size-md .ui-button-icon[data-v-a2969a5c] i:not([class*=size-]){width:18px;height:18px}.ui-button.icon-size-lg .ui-button-icon[data-v-a2969a5c] i:not([class*=size-]){width:20px;height:20px}.ui-button.shape-rounded[data-v-a2969a5c]{border-radius:6px}.ui-button.shape-pill[data-v-a2969a5c]{border-radius:9999px}.ui-button.shape-circle[data-v-a2969a5c]{border-radius:50%}.ui-button.size-xs[data-v-a2969a5c]{min-width:52px}.ui-button.size-sm[data-v-a2969a5c]{min-width:60px}.ui-button.size-md[data-v-a2969a5c]{min-width:68px}.ui-button.size-lg[data-v-a2969a5c]{min-width:84px}.ui-button.is-icon-only[data-v-a2969a5c]{padding:0;min-width:auto}.ui-button.is-icon-only.size-xs[data-v-a2969a5c]{width:24px;min-width:24px}.ui-button.is-icon-only.size-sm[data-v-a2969a5c]{width:28px;min-width:28px}.ui-button.is-icon-only.size-md[data-v-a2969a5c]{width:32px;min-width:32px}.ui-button.is-icon-only.size-lg[data-v-a2969a5c]{width:40px;min-width:40px}.ui-button.variant-primary[data-v-a2969a5c]{background-color:var(--color-primary);color:#fff}@media(hover:hover){.ui-button.variant-primary[data-v-a2969a5c]:hover:not(:disabled):not([aria-disabled=true]){background-color:var(--color-primary-hover)}}.ui-button.variant-primary[data-v-a2969a5c]:active:not(:disabled):not([aria-disabled=true]){background-color:var(--color-primary-dark)}.ui-button.variant-secondary[data-v-a2969a5c]{background-color:#fff;border-color:var(--color-border);color:var(--color-text-primary)}@media(hover:hover){.ui-button.variant-secondary[data-v-a2969a5c]:hover:not(:disabled):not([aria-disabled=true]){background-color:var(--color-background);border-color:var(--color-text-primary)}}.ui-button.variant-secondary[data-v-a2969a5c]:active:not(:disabled):not([aria-disabled=true]){background-color:var(--color-border-light);border-color:var(--color-text-primary)}.ui-button.variant-ghost[data-v-a2969a5c]{background-color:transparent;color:var(--color-text-secondary);min-width:auto}@media(hover:hover){.ui-button.variant-ghost[data-v-a2969a5c]:hover:not(:disabled):not([aria-disabled=true]){background-color:var(--color-background);color:var(--color-text-heading-sub)}}.ui-button.variant-ghost[data-v-a2969a5c]:active:not(:disabled):not([aria-disabled=true]){background-color:var(--color-border-light)}.ui-button.variant-danger[data-v-a2969a5c]{background-color:var(--color-danger);color:#fff}.ui-button.variant-danger[data-v-a2969a5c]:focus-visible{outline-color:var(--color-danger)}@media(hover:hover){.ui-button.variant-danger[data-v-a2969a5c]:hover:not(:disabled):not([aria-disabled=true]){background-color:var(--color-danger-hover)}}.ui-button.variant-danger[data-v-a2969a5c]:active:not(:disabled):not([aria-disabled=true]){background-color:var(--color-danger-dark)}.ui-button.is-disabled[data-v-a2969a5c],.ui-button[aria-disabled=true][data-v-a2969a5c]{opacity:.5;cursor:not-allowed}.ui-button.is-loading[data-v-a2969a5c]{cursor:wait}.ui-button.is-full[data-v-a2969a5c]{width:100%}.ui-button-icon[data-v-a2969a5c]{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}.ui-button-spinner[data-v-a2969a5c]{display:inline-block;flex-shrink:0;border-style:solid;border-color:currentColor;border-right-color:transparent;border-radius:50%;animation:ui-button-spin-a2969a5c .6s linear infinite}@keyframes ui-button-spin-a2969a5c{to{transform:rotate(360deg)}}.ui-input-outer[data-v-e12a2f24]{flex:1;min-width:0}.ui-input-wrap[data-v-e12a2f24]{display:inline-flex;align-items:center;width:100%;background-color:#fff;border:1px solid var(--color-border);overflow:hidden;transition:border-color .2s ease}@media(hover:hover){.ui-input-wrap[data-v-e12a2f24]:hover:not(.is-disabled){border-color:var(--color-primary)}}.ui-input-wrap.is-focused[data-v-e12a2f24]:not(.is-disabled){border-color:var(--color-primary)}.ui-input-wrap.size-sm[data-v-e12a2f24]{height:28px;font-size:13px}.ui-input-wrap.size-sm .ui-input[data-v-e12a2f24]{padding:0 10px}.ui-input-wrap.size-sm .ui-input-icon.is-left[data-v-e12a2f24]{padding-left:10px}.ui-input-wrap.size-sm .ui-input-icon.is-right[data-v-e12a2f24]{padding-right:10px}.ui-input-wrap.size-sm.has-icon-left .ui-input[data-v-e12a2f24]{padding-left:4px}.ui-input-wrap.size-sm.has-icon-right .ui-input[data-v-e12a2f24]{padding-right:4px}.ui-input-wrap.size-sm .ui-input-icon[data-v-e12a2f24] i:not([class*=size-]){width:16px;height:16px}.ui-input-wrap.size-md[data-v-e12a2f24]{height:32px;font-size:14px}.ui-input-wrap.size-md .ui-input[data-v-e12a2f24]{padding:0 12px}.ui-input-wrap.size-md .ui-input-icon.is-left[data-v-e12a2f24]{padding-left:12px}.ui-input-wrap.size-md .ui-input-icon.is-right[data-v-e12a2f24]{padding-right:12px}.ui-input-wrap.size-md.has-icon-left .ui-input[data-v-e12a2f24]{padding-left:4px}.ui-input-wrap.size-md.has-icon-right .ui-input[data-v-e12a2f24]{padding-right:4px}.ui-input-wrap.size-md .ui-input-icon[data-v-e12a2f24] i:not([class*=size-]){width:18px;height:18px}.ui-input-wrap.size-lg[data-v-e12a2f24]{height:40px;font-size:15px}.ui-input-wrap.size-lg .ui-input[data-v-e12a2f24]{padding:0 16px}.ui-input-wrap.size-lg .ui-input-icon.is-left[data-v-e12a2f24]{padding-left:16px}.ui-input-wrap.size-lg .ui-input-icon.is-right[data-v-e12a2f24]{padding-right:16px}.ui-input-wrap.size-lg.has-icon-left .ui-input[data-v-e12a2f24]{padding-left:4px}.ui-input-wrap.size-lg.has-icon-right .ui-input[data-v-e12a2f24]{padding-right:4px}.ui-input-wrap.size-lg .ui-input-icon[data-v-e12a2f24] i:not([class*=size-]){width:20px;height:20px}.ui-input-wrap.size-auth[data-v-e12a2f24]{height:44px;font-size:16px}.ui-input-wrap.size-auth .ui-input[data-v-e12a2f24]{padding:0 10px}.ui-input-wrap.size-auth .ui-input-icon.is-left[data-v-e12a2f24]{padding-left:10px}.ui-input-wrap.size-auth .ui-input-icon.is-right[data-v-e12a2f24]{padding-right:10px}.ui-input-wrap.size-auth.has-icon-left .ui-input[data-v-e12a2f24]{padding-left:4px}.ui-input-wrap.size-auth.has-icon-right .ui-input[data-v-e12a2f24]{padding-right:4px}.ui-input-wrap.size-auth .ui-input-icon[data-v-e12a2f24] i:not([class*=size-]){width:18px;height:18px}.ui-input-wrap.icon-size-xs .ui-input-icon[data-v-e12a2f24] i:not([class*=size-]){width:12px;height:12px}.ui-input-wrap.icon-size-sm .ui-input-icon[data-v-e12a2f24] i:not([class*=size-]){width:16px;height:16px}.ui-input-wrap.icon-size-md .ui-input-icon[data-v-e12a2f24] i:not([class*=size-]){width:18px;height:18px}.ui-input-wrap.icon-size-lg .ui-input-icon[data-v-e12a2f24] i:not([class*=size-]){width:20px;height:20px}.ui-input-wrap.shape-rounded[data-v-e12a2f24]{border-radius:6px}.ui-input-wrap.shape-pill[data-v-e12a2f24]{border-radius:9999px}.ui-input-wrap.is-disabled[data-v-e12a2f24]{opacity:.5;cursor:not-allowed}.ui-input[data-v-e12a2f24]{flex:1;min-width:0;width:100%;height:100%;border:0;background:transparent;font:inherit;font-weight:500;line-height:1.5;color:var(--color-text-primary);outline:none}.ui-input[data-v-e12a2f24]::placeholder{color:#aebccb}.ui-input[data-v-e12a2f24]:disabled{cursor:not-allowed}.ui-input[data-v-e12a2f24]:-webkit-autofill,.ui-input[data-v-e12a2f24]:-webkit-autofill:hover,.ui-input[data-v-e12a2f24]:-webkit-autofill:focus{-webkit-box-shadow:0 0 0 1000px #fff inset;-webkit-text-fill-color:var(--color-text-primary);transition:background-color 5000s ease-in-out 0s}.ui-input-icon[data-v-e12a2f24]{display:inline-flex;align-items:center;flex-shrink:0;color:var(--color-text-secondary)}.ui-input-icon.is-search[data-v-e12a2f24]{border:0;background:transparent;padding:0;color:inherit;cursor:pointer}.ui-input-icon.is-search[data-v-e12a2f24]:disabled{cursor:not-allowed;opacity:.6}.ui-input-icon.is-search[data-v-e12a2f24]:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ui-input-desc[data-v-e12a2f24]{margin-top:4px;font-size:.75rem;font-weight:450;line-height:150%;color:var(--color-text-secondary);line-height:1.5}
@@ -0,0 +1,292 @@
1
+ import { defineComponent as M, ref as k, openBlock as u, createBlock as Q, resolveDynamicComponent as X, normalizeClass as B, withCtx as Y, createElementBlock as f, renderSlot as $, createCommentVNode as y, useAttrs as _, computed as h, useId as ee, normalizeStyle as te, createElementVNode as z, mergeProps as ae, withKeys as ie, toDisplayString as le } from "vue";
2
+ const ne = {
3
+ key: 0,
4
+ class: "ui-button-spinner",
5
+ "aria-hidden": "true"
6
+ }, oe = {
7
+ key: 1,
8
+ class: "ui-button-icon"
9
+ }, se = {
10
+ key: 2,
11
+ class: "ui-button-text"
12
+ }, de = {
13
+ key: 3,
14
+ class: "ui-button-icon"
15
+ }, ue = /* @__PURE__ */ M({
16
+ __name: "UiButton",
17
+ props: {
18
+ variant: { default: "primary" },
19
+ size: { default: "md" },
20
+ iconSize: {},
21
+ shape: { default: "rounded" },
22
+ as: { default: "button" },
23
+ type: { default: "button" },
24
+ href: {},
25
+ target: {},
26
+ disabled: { type: Boolean, default: !1 },
27
+ loading: { type: Boolean, default: !1 },
28
+ fullWidth: { type: Boolean, default: !1 },
29
+ iconOnly: { type: Boolean, default: !1 },
30
+ ariaLabel: {}
31
+ },
32
+ emits: ["click"],
33
+ setup(e, { expose: g, emit: b }) {
34
+ const a = e, c = b, v = (n) => {
35
+ if (a.disabled || a.loading) {
36
+ n.preventDefault(), n.stopPropagation();
37
+ return;
38
+ }
39
+ c("click", n);
40
+ }, m = k(null);
41
+ return g({
42
+ focus: () => {
43
+ var n;
44
+ return (n = m.value) == null ? void 0 : n.focus();
45
+ },
46
+ blur: () => {
47
+ var n;
48
+ return (n = m.value) == null ? void 0 : n.blur();
49
+ },
50
+ el: m
51
+ }), (n, S) => (u(), Q(X(e.as), {
52
+ ref_key: "rootEl",
53
+ ref: m,
54
+ class: B(["ui-button", [
55
+ `variant-${e.variant}`,
56
+ `size-${e.size}`,
57
+ `shape-${e.shape}`,
58
+ e.iconSize ? `icon-size-${e.iconSize}` : null,
59
+ {
60
+ "is-disabled": e.disabled,
61
+ "is-loading": e.loading,
62
+ "is-full": e.fullWidth,
63
+ "is-icon-only": e.iconOnly
64
+ }
65
+ ]]),
66
+ type: e.as === "button" ? e.type : void 0,
67
+ href: e.as === "a" ? e.href : void 0,
68
+ target: e.as === "a" ? e.target : void 0,
69
+ rel: e.as === "a" && e.target === "_blank" ? "noopener noreferrer" : void 0,
70
+ disabled: e.as === "button" && (e.disabled || e.loading) ? !0 : void 0,
71
+ "aria-disabled": e.as === "a" && (e.disabled || e.loading) ? "true" : void 0,
72
+ tabindex: e.as === "a" && (e.disabled || e.loading) ? -1 : void 0,
73
+ "aria-busy": e.loading || void 0,
74
+ "aria-label": e.ariaLabel,
75
+ onClick: v
76
+ }, {
77
+ default: Y(() => [
78
+ e.loading ? (u(), f("span", ne)) : n.$slots["icon-left"] ? (u(), f("span", oe, [
79
+ $(n.$slots, "icon-left", {}, void 0, !0)
80
+ ])) : y("", !0),
81
+ n.$slots.default && !e.iconOnly ? (u(), f("span", se, [
82
+ $(n.$slots, "default", {}, void 0, !0)
83
+ ])) : y("", !0),
84
+ n.$slots["icon-right"] && !e.loading ? (u(), f("span", de, [
85
+ $(n.$slots, "icon-right", {}, void 0, !0)
86
+ ])) : y("", !0)
87
+ ]),
88
+ _: 3
89
+ }, 8, ["class", "type", "href", "target", "rel", "disabled", "aria-disabled", "tabindex", "aria-busy", "aria-label"]));
90
+ }
91
+ }), O = (e, g) => {
92
+ const b = e.__vccOpts || e;
93
+ for (const [a, c] of g)
94
+ b[a] = c;
95
+ return b;
96
+ }, ye = /* @__PURE__ */ O(ue, [["__scopeId", "data-v-a2969a5c"]]), ce = {
97
+ key: 0,
98
+ class: "ui-input-icon is-left"
99
+ }, re = ["id", "type", "role", "inputmode", "value", "placeholder", "disabled", "readonly", "required", "autocomplete", "name", "maxlength", "aria-describedby"], fe = ["disabled", "aria-label"], me = {
100
+ key: 2,
101
+ class: "ui-input-icon is-right"
102
+ }, ve = ["id"], be = /* @__PURE__ */ M({
103
+ inheritAttrs: !1,
104
+ __name: "UiInput",
105
+ props: {
106
+ modelValue: { default: "" },
107
+ type: { default: "text" },
108
+ placeholder: { default: "" },
109
+ disabled: { type: Boolean, default: !1 },
110
+ readonly: { type: Boolean, default: !1 },
111
+ required: { type: Boolean, default: !1 },
112
+ autocomplete: { default: void 0 },
113
+ name: { default: void 0 },
114
+ id: { default: void 0 },
115
+ maxLength: { default: void 0 },
116
+ min: { default: void 0 },
117
+ max: { default: void 0 },
118
+ step: { default: void 0 },
119
+ size: { default: "md" },
120
+ iconSize: {},
121
+ shape: { default: "rounded" },
122
+ desc: { default: "" },
123
+ numberOnly: { type: Boolean, default: !1 },
124
+ allowDecimal: { type: Boolean, default: !1 },
125
+ allowNegative: { type: Boolean, default: !1 },
126
+ decimals: { default: void 0 },
127
+ searchAriaLabel: { default: "검색" }
128
+ },
129
+ emits: ["update:modelValue", "enter", "search"],
130
+ setup(e, { expose: g, emit: b }) {
131
+ const a = e, c = b, v = k(), m = k(!1), n = k(!1), S = _(), p = h(() => {
132
+ const { class: t, style: l, ...s } = S;
133
+ return s;
134
+ }), A = h(() => S.class), L = h(() => S.style ?? void 0), P = ee(), C = h(() => {
135
+ if (a.desc)
136
+ return a.id ? `${a.id}-desc` : `${P}-desc`;
137
+ }), F = h(() => {
138
+ if (a.numberOnly)
139
+ return a.allowDecimal || a.allowNegative ? "decimal" : "numeric";
140
+ }), x = h(() => {
141
+ const t = a.decimals;
142
+ if (t !== void 0 && Number.isInteger(t) && t >= 0)
143
+ return t;
144
+ }), N = (t) => {
145
+ if (typeof a.modelValue == "number") {
146
+ if (t === "" || t === "-") return t;
147
+ const l = parseFloat(t);
148
+ if (!Number.isNaN(l)) return l;
149
+ }
150
+ return t;
151
+ }, V = (t) => {
152
+ let l = "0-9";
153
+ a.allowDecimal && (l += "."), a.allowNegative && (l += "-");
154
+ const s = new RegExp(`[^${l}]`, "g");
155
+ let i = t.replace(s, "");
156
+ if (a.allowNegative) {
157
+ const o = i.startsWith("-");
158
+ i = i.replace(/-/g, ""), o && (i = "-" + i);
159
+ }
160
+ if (a.allowDecimal) {
161
+ const o = i.indexOf(".");
162
+ if (o !== -1) {
163
+ const r = i.slice(0, o);
164
+ let d = i.slice(o + 1).replace(/\./g, "");
165
+ x.value !== void 0 && (d = d.slice(0, x.value)), i = d === "" && r === "" ? "" : r + "." + d;
166
+ }
167
+ }
168
+ return i;
169
+ }, U = (t) => {
170
+ const l = t.trim();
171
+ if (l === "") return "";
172
+ const s = V(l);
173
+ if (s === "" || s === "-") return s;
174
+ let i = parseFloat(s);
175
+ if (Number.isNaN(i)) return s;
176
+ const o = a.min !== void 0 ? Number(a.min) : void 0, r = a.max !== void 0 ? Number(a.max) : void 0, d = a.step !== void 0 ? Number(a.step) : void 0;
177
+ if (o !== void 0 && !Number.isNaN(o) && (i = Math.max(i, o)), r !== void 0 && !Number.isNaN(r) && (i = Math.min(i, r)), d !== void 0 && d > 0 && !Number.isNaN(d)) {
178
+ const w = o !== void 0 && !Number.isNaN(o) ? o : 0;
179
+ i = w + Math.round((i - w) / d) * d, o !== void 0 && !Number.isNaN(o) && (i = Math.max(i, o)), r !== void 0 && !Number.isNaN(r) && (i = Math.min(i, r));
180
+ const j = (String(a.step).split(".")[1] || "").length, G = (String(a.min ?? "").split(".")[1] || "").length, I = Math.max(j, G, a.allowDecimal ? 2 : 0), E = x.value, J = E !== void 0 ? Math.min(I, E) : I;
181
+ i = Number(i.toFixed(J));
182
+ }
183
+ return String(i);
184
+ }, q = () => {
185
+ m.value = !0;
186
+ }, K = (t) => {
187
+ m.value = !1;
188
+ const l = t.target;
189
+ if (!a.numberOnly || a.min === void 0 && a.max === void 0 && a.step === void 0) return;
190
+ const s = U(l.value);
191
+ s !== l.value && (l.value = s, c("update:modelValue", N(s)));
192
+ }, D = (t) => {
193
+ if (a.numberOnly) {
194
+ const l = V(t.value);
195
+ l !== t.value && (t.value = l), c("update:modelValue", N(l));
196
+ } else
197
+ c("update:modelValue", N(t.value));
198
+ }, R = (t) => {
199
+ n.value || D(t.target);
200
+ }, W = () => {
201
+ n.value = !0;
202
+ }, Z = (t) => {
203
+ n.value = !1, D(t.target);
204
+ }, H = (t) => {
205
+ const l = t.target;
206
+ c("enter", N(l.value));
207
+ }, T = () => {
208
+ var t;
209
+ a.disabled || c("search", N(((t = v.value) == null ? void 0 : t.value) ?? ""));
210
+ };
211
+ return g({
212
+ focus: () => {
213
+ var t;
214
+ return (t = v.value) == null ? void 0 : t.focus();
215
+ },
216
+ blur: () => {
217
+ var t;
218
+ return (t = v.value) == null ? void 0 : t.blur();
219
+ },
220
+ el: v
221
+ }), (t, l) => (u(), f("div", {
222
+ class: B(["ui-input-outer", [A.value, { "has-desc": !!e.desc }]]),
223
+ style: te(L.value)
224
+ }, [
225
+ z("div", {
226
+ class: B(["ui-input-wrap", [
227
+ `size-${e.size}`,
228
+ `shape-${e.shape}`,
229
+ e.iconSize ? `icon-size-${e.iconSize}` : null,
230
+ {
231
+ "is-disabled": e.disabled,
232
+ "is-focused": m.value,
233
+ "has-icon-left": !!t.$slots["icon-left"],
234
+ "has-icon-right": !!t.$slots["icon-right"] || e.type === "search"
235
+ }
236
+ ]])
237
+ }, [
238
+ t.$slots["icon-left"] ? (u(), f("span", ce, [
239
+ $(t.$slots, "icon-left", {}, void 0, !0)
240
+ ])) : y("", !0),
241
+ z("input", ae(p.value, {
242
+ id: e.id,
243
+ ref_key: "inputRef",
244
+ ref: v,
245
+ class: "ui-input",
246
+ type: e.type === "search" ? "text" : e.type,
247
+ role: e.type === "search" ? "searchbox" : void 0,
248
+ inputmode: F.value,
249
+ value: e.modelValue,
250
+ placeholder: e.placeholder,
251
+ disabled: e.disabled,
252
+ readonly: e.readonly,
253
+ required: e.required || void 0,
254
+ autocomplete: e.autocomplete,
255
+ name: e.name,
256
+ maxlength: e.maxLength,
257
+ "aria-describedby": C.value,
258
+ onInput: R,
259
+ onCompositionstart: W,
260
+ onCompositionend: Z,
261
+ onFocus: q,
262
+ onBlur: K,
263
+ onKeydown: ie(H, ["enter"])
264
+ }), null, 16, re),
265
+ e.type === "search" ? (u(), f("button", {
266
+ key: 1,
267
+ type: "button",
268
+ class: "ui-input-icon is-right is-search",
269
+ disabled: e.disabled,
270
+ "aria-label": e.searchAriaLabel,
271
+ onClick: T
272
+ }, [...l[0] || (l[0] = [
273
+ z("i", { class: "icon-search" }, null, -1)
274
+ ])], 8, fe)) : t.$slots["icon-right"] ? (u(), f("span", me, [
275
+ $(t.$slots, "icon-right", {}, void 0, !0)
276
+ ])) : y("", !0)
277
+ ], 2),
278
+ e.desc ? (u(), f("p", {
279
+ key: 0,
280
+ id: C.value,
281
+ class: "ui-input-desc"
282
+ }, le(e.desc), 9, ve)) : y("", !0)
283
+ ], 6));
284
+ }
285
+ }), ge = /* @__PURE__ */ O(be, [["__scopeId", "data-v-e12a2f24"]]), Ne = ["xs", "sm", "md", "lg"], $e = ["sm", "md", "lg", "auth"], Se = ["rounded", "pill", "circle"];
286
+ export {
287
+ $e as INPUT_SIZES,
288
+ Se as SHAPES,
289
+ Ne as SIZES,
290
+ ye as UiButton,
291
+ ge as UiInput
292
+ };
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@leechanyong/ispark-ui",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "description": "Ispark Design System UI Library (Vue 3 + Vite + Storybook)",
6
+ "author": "box3101 <tony.at.cp@gmail.com>",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/box3101/ispark-ui.git"
11
+ },
12
+ "publishConfig": {
13
+ "registry": "https://registry.npmjs.org",
14
+ "access": "public"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "CHANGELOG.md",
20
+ "LICENSE"
21
+ ],
22
+ "main": "./dist/ispark-ui.cjs",
23
+ "module": "./dist/ispark-ui.js",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/ispark-ui.js",
29
+ "require": "./dist/ispark-ui.cjs"
30
+ },
31
+ "./style.css": "./dist/ispark-ui.css",
32
+ "./styles": "./dist/ispark-ui.css"
33
+ },
34
+ "sideEffects": [
35
+ "**/*.css",
36
+ "**/*.scss"
37
+ ],
38
+ "scripts": {
39
+ "dev": "vite",
40
+ "build": "npm run build:icons && vue-tsc --noEmit && vite build",
41
+ "build:icons": "node scripts/build-icons.mjs",
42
+ "preview": "vite preview",
43
+ "storybook": "storybook dev -p 6006",
44
+ "build-storybook": "storybook build",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "typecheck": "vue-tsc --noEmit",
48
+ "prepare": "npm run build",
49
+ "prepublishOnly": "npm run build"
50
+ },
51
+ "peerDependencies": {
52
+ "vue": "^3.5.0"
53
+ },
54
+ "devDependencies": {
55
+ "@storybook/addon-essentials": "^8.6.14",
56
+ "@storybook/test": "^8.6.14",
57
+ "@storybook/vue3-vite": "^8.6.14",
58
+ "@testing-library/vue": "^8.1.0",
59
+ "@vitejs/plugin-vue": "^5.2.1",
60
+ "jsdom": "^25.0.1",
61
+ "sass-embedded": "^1.83.4",
62
+ "storybook": "^8.6.14",
63
+ "typescript": "~5.6.3",
64
+ "vite": "^6.0.7",
65
+ "vite-plugin-dts": "^4.5.4",
66
+ "vitest": "^2.1.8",
67
+ "vue": "^3.5.13",
68
+ "vue-tsc": "^2.2.0"
69
+ }
70
+ }