tyrell-react 1.0.0-TC10
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/LICENSE +21 -0
- package/README.md +410 -0
- package/dist/components/TyButton.d.ts +50 -0
- package/dist/components/TyButton.d.ts.map +1 -0
- package/dist/components/TyButton.js +68 -0
- package/dist/components/TyButton.js.map +1 -0
- package/dist/components/TyCalendar.d.ts +63 -0
- package/dist/components/TyCalendar.d.ts.map +1 -0
- package/dist/components/TyCalendar.js +122 -0
- package/dist/components/TyCalendar.js.map +1 -0
- package/dist/components/TyCalendarMonth.d.ts +32 -0
- package/dist/components/TyCalendarMonth.d.ts.map +1 -0
- package/dist/components/TyCalendarMonth.js +54 -0
- package/dist/components/TyCalendarMonth.js.map +1 -0
- package/dist/components/TyCalendarNavigation.d.ts +21 -0
- package/dist/components/TyCalendarNavigation.d.ts.map +1 -0
- package/dist/components/TyCalendarNavigation.js +50 -0
- package/dist/components/TyCalendarNavigation.js.map +1 -0
- package/dist/components/TyCheckbox.d.ts +39 -0
- package/dist/components/TyCheckbox.d.ts.map +1 -0
- package/dist/components/TyCheckbox.js +79 -0
- package/dist/components/TyCheckbox.js.map +1 -0
- package/dist/components/TyCopy.d.ts +21 -0
- package/dist/components/TyCopy.d.ts.map +1 -0
- package/dist/components/TyCopy.js +42 -0
- package/dist/components/TyCopy.js.map +1 -0
- package/dist/components/TyDatePicker.d.ts +45 -0
- package/dist/components/TyDatePicker.d.ts.map +1 -0
- package/dist/components/TyDatePicker.js +114 -0
- package/dist/components/TyDatePicker.js.map +1 -0
- package/dist/components/TyDropdown.d.ts +51 -0
- package/dist/components/TyDropdown.d.ts.map +1 -0
- package/dist/components/TyDropdown.js +109 -0
- package/dist/components/TyDropdown.js.map +1 -0
- package/dist/components/TyIcon.d.ts +17 -0
- package/dist/components/TyIcon.d.ts.map +1 -0
- package/dist/components/TyIcon.js +41 -0
- package/dist/components/TyIcon.js.map +1 -0
- package/dist/components/TyInput.d.ts +65 -0
- package/dist/components/TyInput.d.ts.map +1 -0
- package/dist/components/TyInput.js +105 -0
- package/dist/components/TyInput.js.map +1 -0
- package/dist/components/TyModal.d.ts +29 -0
- package/dist/components/TyModal.d.ts.map +1 -0
- package/dist/components/TyModal.js +74 -0
- package/dist/components/TyModal.js.map +1 -0
- package/dist/components/TyMultiselect.d.ts +51 -0
- package/dist/components/TyMultiselect.d.ts.map +1 -0
- package/dist/components/TyMultiselect.js +103 -0
- package/dist/components/TyMultiselect.js.map +1 -0
- package/dist/components/TyOption.d.ts +10 -0
- package/dist/components/TyOption.d.ts.map +1 -0
- package/dist/components/TyOption.js +25 -0
- package/dist/components/TyOption.js.map +1 -0
- package/dist/components/TyPopup.d.ts +24 -0
- package/dist/components/TyPopup.d.ts.map +1 -0
- package/dist/components/TyPopup.js +61 -0
- package/dist/components/TyPopup.js.map +1 -0
- package/dist/components/TyRadio.d.ts +20 -0
- package/dist/components/TyRadio.d.ts.map +1 -0
- package/dist/components/TyRadio.js +31 -0
- package/dist/components/TyRadio.js.map +1 -0
- package/dist/components/TyRadioGroup.d.ts +40 -0
- package/dist/components/TyRadioGroup.d.ts.map +1 -0
- package/dist/components/TyRadioGroup.js +58 -0
- package/dist/components/TyRadioGroup.js.map +1 -0
- package/dist/components/TyResizeObserver.d.ts +11 -0
- package/dist/components/TyResizeObserver.d.ts.map +1 -0
- package/dist/components/TyResizeObserver.js +28 -0
- package/dist/components/TyResizeObserver.js.map +1 -0
- package/dist/components/TyScrollContainer.d.ts +25 -0
- package/dist/components/TyScrollContainer.d.ts.map +1 -0
- package/dist/components/TyScrollContainer.js +43 -0
- package/dist/components/TyScrollContainer.js.map +1 -0
- package/dist/components/TyStep.d.ts +17 -0
- package/dist/components/TyStep.d.ts.map +1 -0
- package/dist/components/TyStep.js +35 -0
- package/dist/components/TyStep.js.map +1 -0
- package/dist/components/TySwitch.d.ts +35 -0
- package/dist/components/TySwitch.d.ts.map +1 -0
- package/dist/components/TySwitch.js +54 -0
- package/dist/components/TySwitch.js.map +1 -0
- package/dist/components/TyTab.d.ts +13 -0
- package/dist/components/TyTab.d.ts.map +1 -0
- package/dist/components/TyTab.js +32 -0
- package/dist/components/TyTab.js.map +1 -0
- package/dist/components/TyTabs.d.ts +23 -0
- package/dist/components/TyTabs.d.ts.map +1 -0
- package/dist/components/TyTabs.js +48 -0
- package/dist/components/TyTabs.js.map +1 -0
- package/dist/components/TyTag.d.ts +22 -0
- package/dist/components/TyTag.d.ts.map +1 -0
- package/dist/components/TyTag.js +45 -0
- package/dist/components/TyTag.js.map +1 -0
- package/dist/components/TyTextarea.d.ts +37 -0
- package/dist/components/TyTextarea.d.ts.map +1 -0
- package/dist/components/TyTextarea.js +93 -0
- package/dist/components/TyTextarea.js.map +1 -0
- package/dist/components/TyTooltip.d.ts +17 -0
- package/dist/components/TyTooltip.d.ts.map +1 -0
- package/dist/components/TyTooltip.js +40 -0
- package/dist/components/TyTooltip.js.map +1 -0
- package/dist/components/TyWizard.d.ts +26 -0
- package/dist/components/TyWizard.d.ts.map +1 -0
- package/dist/components/TyWizard.js +50 -0
- package/dist/components/TyWizard.js.map +1 -0
- package/dist/components/index.d.ts +105 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +112 -0
- package/dist/components/index.js.map +1 -0
- package/package.json +46 -0
- package/src/components/EventConventionTest.tsx +155 -0
- package/src/components/TyButton.tsx +145 -0
- package/src/components/TyCalendar.tsx +244 -0
- package/src/components/TyCalendarMonth.tsx +108 -0
- package/src/components/TyCalendarNavigation.tsx +91 -0
- package/src/components/TyCheckbox.tsx +149 -0
- package/src/components/TyCopy.tsx +78 -0
- package/src/components/TyDatePicker.tsx +216 -0
- package/src/components/TyDropdown.tsx +218 -0
- package/src/components/TyIcon.tsx +72 -0
- package/src/components/TyInput.tsx +207 -0
- package/src/components/TyModal.tsx +142 -0
- package/src/components/TyMultiselect.tsx +200 -0
- package/src/components/TyOption.tsx +42 -0
- package/src/components/TyPopup.tsx +111 -0
- package/src/components/TyRadio.tsx +56 -0
- package/src/components/TyRadioGroup.tsx +121 -0
- package/src/components/TyResizeObserver.tsx +54 -0
- package/src/components/TyScrollContainer.tsx +87 -0
- package/src/components/TyStep.tsx +71 -0
- package/src/components/TySwitch.tsx +108 -0
- package/src/components/TyTab.tsx +63 -0
- package/src/components/TyTabs.tsx +93 -0
- package/src/components/TyTag.tsx +79 -0
- package/src/components/TyTextarea.tsx +154 -0
- package/src/components/TyTooltip.tsx +83 -0
- package/src/components/TyWizard.tsx +99 -0
- package/src/components/index.ts +251 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 gersak
|
|
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,410 @@
|
|
|
1
|
+
# tyrell-react
|
|
2
|
+
|
|
3
|
+
**React wrappers for Ty Web Components** - bringing framework-agnostic web components to React with full TypeScript support.
|
|
4
|
+
|
|
5
|
+
## 🎯 Philosophy
|
|
6
|
+
|
|
7
|
+
Ty web components are **distributed via CDN** and loaded as standard web components. These React wrappers provide:
|
|
8
|
+
- ✅ **React-friendly API** - Props instead of attributes
|
|
9
|
+
- ✅ **TypeScript types** - Full type safety
|
|
10
|
+
- ✅ **Event handling** - React synthetic events
|
|
11
|
+
- ✅ **Ref forwarding** - Direct DOM access
|
|
12
|
+
- ✅ **Zero bundle overhead** - Just thin wrappers (~2KB)
|
|
13
|
+
|
|
14
|
+
## 📦 Installation
|
|
15
|
+
|
|
16
|
+
### Step 1: Load Ty Web Components (CDN)
|
|
17
|
+
|
|
18
|
+
Add to your `index.html`:
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<!DOCTYPE html>
|
|
22
|
+
<html>
|
|
23
|
+
<head>
|
|
24
|
+
<!-- Ty Web Components & Styles via CDN -->
|
|
25
|
+
<script src="https://cdn.jsdelivr.net/npm/tyrell-components@latest/dist/tyrell.js"></script>
|
|
26
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tyrell-components@latest/css/tyrell.css">
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<div id="root"></div>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Step 2: Install React Wrappers
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install tyrell-react
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
That's it! No build complexity, no bundler configuration.
|
|
41
|
+
|
|
42
|
+
## 🚀 Quick Start
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import React, { useState } from 'react';
|
|
46
|
+
import { TyButton, TyInput, TyModal } from 'tyrell-react';
|
|
47
|
+
|
|
48
|
+
function App() {
|
|
49
|
+
const [value, setValue] = useState('');
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div>
|
|
53
|
+
<TyButton flavor="primary" onClick={() => alert('Hello!')}>
|
|
54
|
+
Click Me
|
|
55
|
+
</TyButton>
|
|
56
|
+
|
|
57
|
+
<TyInput
|
|
58
|
+
placeholder="Enter text..."
|
|
59
|
+
value={value}
|
|
60
|
+
onChange={(e) => setValue(e.detail.value)} // Fires on every keystroke
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 📚 Available Components
|
|
68
|
+
|
|
69
|
+
All 18 components wrapped:
|
|
70
|
+
|
|
71
|
+
| Component | Description |
|
|
72
|
+
|-----------|-------------|
|
|
73
|
+
| `TyButton` | Semantic button with multiple flavors |
|
|
74
|
+
| `TyInput` | Form input with validation |
|
|
75
|
+
| `TyTextarea` | Multi-line text input |
|
|
76
|
+
| `TyCheckbox` | Checkbox with custom styling |
|
|
77
|
+
| `TyDropdown` | Dropdown selection |
|
|
78
|
+
| `TyOption` | Dropdown option |
|
|
79
|
+
| `TyMultiselect` | Multi-value selection |
|
|
80
|
+
| `TyTag` | Tag/badge component |
|
|
81
|
+
| `TyModal` | Modal dialogs |
|
|
82
|
+
| `TyPopup` | Smart popup positioning |
|
|
83
|
+
| `TyTooltip` | Tooltip component |
|
|
84
|
+
| `TyIcon` | Icon component (3000+ icons) |
|
|
85
|
+
| `TyCalendar` | Full calendar |
|
|
86
|
+
| `TyCalendarMonth` | Month view |
|
|
87
|
+
| `TyCalendarNavigation` | Calendar navigation |
|
|
88
|
+
| `TyDatePicker` | Date picker with calendar |
|
|
89
|
+
| `TyTabs` | Tab container |
|
|
90
|
+
| `TyTab` | Individual tab |
|
|
91
|
+
| `TyWizard` | Multi-step wizard/stepper |
|
|
92
|
+
| `TyStep` | Individual wizard step |
|
|
93
|
+
| `TyResizeObserver` | Element size observer |
|
|
94
|
+
| `TyScrollContainer` | Scroll wrapper with edge shadows |
|
|
95
|
+
| `TyCopy` | Copy-to-clipboard field |
|
|
96
|
+
|
|
97
|
+
## ⚡ Event Handling (React Convention)
|
|
98
|
+
|
|
99
|
+
Ty React wrappers follow React conventions for event handling:
|
|
100
|
+
|
|
101
|
+
### Input Components (Input, Textarea, Checkbox)
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { TyInput } from 'tyrell-react';
|
|
105
|
+
|
|
106
|
+
function SearchBox() {
|
|
107
|
+
const [query, setQuery] = useState('');
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<TyInput
|
|
111
|
+
value={query}
|
|
112
|
+
// ✅ onChange fires on every keystroke (React convention)
|
|
113
|
+
onChange={(e) => setQuery(e.detail.value)}
|
|
114
|
+
|
|
115
|
+
// ✅ onChangeCommit fires on blur (optional - for validation)
|
|
116
|
+
onChangeCommit={(e) => console.log('Final value:', e.detail.value)}
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Key Points:**
|
|
123
|
+
- `onChange` → Fires on **every keystroke** (matches React's `<input onChange>`)
|
|
124
|
+
- `onChangeCommit` → Fires on **blur** if value changed (optional)
|
|
125
|
+
- This differs from native DOM where `onchange` fires on blur
|
|
126
|
+
|
|
127
|
+
### Selection Components (Dropdown, Calendar, etc.)
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { TyDropdown, TyOption } from 'tyrell-react';
|
|
131
|
+
|
|
132
|
+
function CountrySelector() {
|
|
133
|
+
return (
|
|
134
|
+
<TyDropdown
|
|
135
|
+
// onChange fires when selection changes
|
|
136
|
+
onChange={(e) => console.log('Selected:', e.detail.value)}
|
|
137
|
+
>
|
|
138
|
+
<TyOption value="us">United States</TyOption>
|
|
139
|
+
<TyOption value="ca">Canada</TyOption>
|
|
140
|
+
</TyDropdown>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
For selection components, `onChange` fires when the selection changes (as expected).
|
|
146
|
+
|
|
147
|
+
## 💡 Usage Examples
|
|
148
|
+
|
|
149
|
+
### Form with Validation
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
import { TyInput, TyDropdown, TyOption, TyButton } from 'tyrell-react';
|
|
153
|
+
|
|
154
|
+
function ContactForm() {
|
|
155
|
+
const handleSubmit = (e: React.FormEvent) => {
|
|
156
|
+
e.preventDefault();
|
|
157
|
+
const formData = new FormData(e.currentTarget as HTMLFormElement);
|
|
158
|
+
console.log(Object.fromEntries(formData));
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<form onSubmit={handleSubmit}>
|
|
163
|
+
<TyInput
|
|
164
|
+
name="email"
|
|
165
|
+
type="email"
|
|
166
|
+
required
|
|
167
|
+
placeholder="your@email.com"
|
|
168
|
+
/>
|
|
169
|
+
|
|
170
|
+
<TyDropdown name="role" required>
|
|
171
|
+
<TyOption value="admin">Administrator</TyOption>
|
|
172
|
+
<TyOption value="user">User</TyOption>
|
|
173
|
+
</TyDropdown>
|
|
174
|
+
|
|
175
|
+
<TyButton type="submit" flavor="primary">
|
|
176
|
+
Submit
|
|
177
|
+
</TyButton>
|
|
178
|
+
</form>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Modal with Imperative API
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
import { useRef } from 'react';
|
|
187
|
+
import { TyModal, TyButton, type TyModalRef } from 'tyrell-react';
|
|
188
|
+
|
|
189
|
+
function ModalExample() {
|
|
190
|
+
const modalRef = useRef<TyModalRef>(null);
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<>
|
|
194
|
+
<TyButton onClick={() => modalRef.current?.show()}>
|
|
195
|
+
Open Modal
|
|
196
|
+
</TyButton>
|
|
197
|
+
|
|
198
|
+
<TyModal
|
|
199
|
+
ref={modalRef}
|
|
200
|
+
onClose={(e) => console.log('Closed:', e.detail.reason)}
|
|
201
|
+
>
|
|
202
|
+
<h2>Modal Content</h2>
|
|
203
|
+
<TyButton onClick={() => modalRef.current?.hide()}>
|
|
204
|
+
Close
|
|
205
|
+
</TyButton>
|
|
206
|
+
</TyModal>
|
|
207
|
+
</>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Calendar with Custom Rendering
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
import { useState } from 'react';
|
|
216
|
+
import { TyCalendar } from 'tyrell-react';
|
|
217
|
+
|
|
218
|
+
function CalendarExample() {
|
|
219
|
+
const [selected, setSelected] = useState<Date | null>(null);
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<TyCalendar
|
|
223
|
+
value={selected?.getTime()}
|
|
224
|
+
onChange={(e) => setSelected(new Date(e.detail.date))}
|
|
225
|
+
min="2024-01-01"
|
|
226
|
+
max="2024-12-31"
|
|
227
|
+
/>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 🪟 Surfaces
|
|
233
|
+
|
|
234
|
+
The Tyrell design system has five surface levels (background + shadow). They ship as
|
|
235
|
+
CSS utility classes — apply them directly to any element. There is no wrapper component
|
|
236
|
+
to learn:
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
function Dashboard() {
|
|
240
|
+
return (
|
|
241
|
+
<section className="ty-elevated p-6 rounded-lg">
|
|
242
|
+
<h2>Card title</h2>
|
|
243
|
+
<p>Sits above the page background.</p>
|
|
244
|
+
</section>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
| Class | Use for |
|
|
250
|
+
|----------------|--------------------------------------|
|
|
251
|
+
| `ty-floating` | modals, dropdowns, tooltips |
|
|
252
|
+
| `ty-elevated` | cards, panels, sidebars |
|
|
253
|
+
| `ty-content` | main content areas |
|
|
254
|
+
| `ty-canvas` | app/page background |
|
|
255
|
+
| `ty-input` | form control surface |
|
|
256
|
+
|
|
257
|
+
**Golden rule:** use Tyrell surface/colour classes for colour, Tailwind (or your own utilities)
|
|
258
|
+
for everything else (spacing, layout, typography). Don't mix `bg-blue-500` with surfaces.
|
|
259
|
+
|
|
260
|
+
## 🎨 Icons (3000+ Available)
|
|
261
|
+
|
|
262
|
+
Import only the icons you need (tree-shaking) and register them once at app startup
|
|
263
|
+
via the global `window.tyIcons` API exposed by `tyrell-components`:
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
// app/icons.ts (or wherever your app boots)
|
|
267
|
+
import { check, heart, star } from 'tyrell-components/icons/lucide';
|
|
268
|
+
|
|
269
|
+
export function registerIcons() {
|
|
270
|
+
window.tyIcons.register({ check, heart, star });
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
// app/layout.tsx (call once, e.g. in a top-level effect)
|
|
276
|
+
'use client';
|
|
277
|
+
import { useEffect } from 'react';
|
|
278
|
+
import { registerIcons } from './icons';
|
|
279
|
+
|
|
280
|
+
export default function RootLayout({ children }) {
|
|
281
|
+
useEffect(() => { registerIcons(); }, []);
|
|
282
|
+
return <>{children}</>;
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Then use icons anywhere in React:
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
import { TyIcon, TyButton } from 'tyrell-react';
|
|
290
|
+
|
|
291
|
+
function IconExample() {
|
|
292
|
+
return (
|
|
293
|
+
<>
|
|
294
|
+
<TyIcon name="check" size="lg" />
|
|
295
|
+
|
|
296
|
+
<TyButton flavor="primary">
|
|
297
|
+
<TyIcon name="heart" />
|
|
298
|
+
Like
|
|
299
|
+
</TyButton>
|
|
300
|
+
</>
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
CDN alternative (vanilla HTML, no bundler):
|
|
306
|
+
|
|
307
|
+
```html
|
|
308
|
+
<script type="module">
|
|
309
|
+
import { check, heart, star }
|
|
310
|
+
from 'https://cdn.jsdelivr.net/npm/tyrell-components@latest/lib/icons/lucide.js';
|
|
311
|
+
|
|
312
|
+
window.tyIcons.register({ check, heart, star });
|
|
313
|
+
</script>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## 📘 TypeScript Support
|
|
317
|
+
|
|
318
|
+
Full TypeScript definitions included:
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import type {
|
|
322
|
+
TyButtonProps,
|
|
323
|
+
TyInputEventDetail,
|
|
324
|
+
TyModalRef,
|
|
325
|
+
TyDropdownEventDetail
|
|
326
|
+
} from 'tyrell-react';
|
|
327
|
+
|
|
328
|
+
// Type-safe props
|
|
329
|
+
const buttonProps: TyButtonProps = {
|
|
330
|
+
flavor: 'primary', // ✅ Autocomplete
|
|
331
|
+
size: 'lg', // ✅ Type-checked
|
|
332
|
+
disabled: false
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// Type-safe event handlers
|
|
336
|
+
const handleChange = (e: CustomEvent<TyInputEventDetail>) => {
|
|
337
|
+
console.log(e.detail.value); // ✅ Typed
|
|
338
|
+
console.log(e.detail.rawValue); // ✅ Typed
|
|
339
|
+
};
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## 🌐 ClojureScript Support
|
|
343
|
+
|
|
344
|
+
Works perfectly with Reagent and UIx:
|
|
345
|
+
|
|
346
|
+
### Reagent
|
|
347
|
+
|
|
348
|
+
```clojure
|
|
349
|
+
(ns my-app.core
|
|
350
|
+
(:require ["tyrell-react" :as ty]))
|
|
351
|
+
|
|
352
|
+
(defn my-component []
|
|
353
|
+
[:div
|
|
354
|
+
[:> ty/TyButton {:flavor "primary"} "Click Me"]
|
|
355
|
+
[:> ty/TyInput {:placeholder "Enter text..."}]])
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### UIx
|
|
359
|
+
|
|
360
|
+
```clojure
|
|
361
|
+
(ns my-app.core
|
|
362
|
+
(:require [uix.core :as uix]
|
|
363
|
+
["tyrell-react" :refer [TyButton TyInput]]))
|
|
364
|
+
|
|
365
|
+
(defn my-component []
|
|
366
|
+
(uix/view
|
|
367
|
+
[:<>
|
|
368
|
+
[TyButton {:flavor "primary"} "Click Me"]
|
|
369
|
+
[TyInput {:placeholder "Enter text..."}]]))
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## 🔧 Peer Dependencies
|
|
373
|
+
|
|
374
|
+
Only React is required:
|
|
375
|
+
- `react` >=18.0.0
|
|
376
|
+
- `react-dom` >=18.0.0
|
|
377
|
+
|
|
378
|
+
**Note:** The core `tyrell-components` web components are loaded via CDN, not as an npm dependency!
|
|
379
|
+
|
|
380
|
+
## 🌍 Browser Support
|
|
381
|
+
|
|
382
|
+
Modern browsers with Web Components support:
|
|
383
|
+
- Chrome 67+
|
|
384
|
+
- Firefox 63+
|
|
385
|
+
- Safari 13.1+
|
|
386
|
+
- Edge 79+
|
|
387
|
+
|
|
388
|
+
## 📝 Why CDN Distribution?
|
|
389
|
+
|
|
390
|
+
**Ty web components are framework-agnostic** and designed for CDN distribution:
|
|
391
|
+
|
|
392
|
+
✅ **Zero version conflicts** - One version serves all frameworks
|
|
393
|
+
✅ **Smaller bundles** - Web components load once, shared across all React components
|
|
394
|
+
✅ **No build complexity** - Just script tags
|
|
395
|
+
✅ **Better caching** - CDN edge network
|
|
396
|
+
✅ **Framework freedom** - Same components work in React, Vue, Svelte, vanilla JS
|
|
397
|
+
|
|
398
|
+
## 🤝 Contributing
|
|
399
|
+
|
|
400
|
+
This package is part of the [Ty monorepo](https://github.com/gersak/tyrell).
|
|
401
|
+
|
|
402
|
+
## 📄 License
|
|
403
|
+
|
|
404
|
+
MIT License - see [LICENSE](./LICENSE)
|
|
405
|
+
|
|
406
|
+
## 🔗 Links
|
|
407
|
+
|
|
408
|
+
- [Ty Core Package](https://www.npmjs.com/package/tyrell-components)
|
|
409
|
+
- [GitHub Repository](https://github.com/gersak/tyrell)
|
|
410
|
+
- [Documentation](https://tyrell.gersak.dev) (Coming Soon)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type BuiltinFlavor = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'neutral';
|
|
3
|
+
type ShadedFlavor = BuiltinFlavor | `${BuiltinFlavor}+` | `${BuiltinFlavor}-`;
|
|
4
|
+
type ButtonAppearance = 'solid' | 'outlined' | 'ghost';
|
|
5
|
+
export interface TyButtonCSSProperties extends React.CSSProperties {
|
|
6
|
+
'--ty-button-bg'?: string;
|
|
7
|
+
'--ty-button-bg-hover'?: string;
|
|
8
|
+
'--ty-button-color'?: string;
|
|
9
|
+
'--ty-button-border'?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface TyButtonProps extends Omit<React.HTMLAttributes<HTMLElement>, 'style'> {
|
|
12
|
+
style?: TyButtonCSSProperties;
|
|
13
|
+
/**
|
|
14
|
+
* Semantic styling variant. Built-in flavors get themed styles; append `+`
|
|
15
|
+
* for a stronger shade or `-` for a softer one (e.g. `"primary+"`,
|
|
16
|
+
* `"danger-"`). Any other string is passed through as-is — theme it via
|
|
17
|
+
* `--ty-button-*` CSS variables.
|
|
18
|
+
*/
|
|
19
|
+
flavor?: ShadedFlavor | (string & {});
|
|
20
|
+
/**
|
|
21
|
+
* Visual appearance:
|
|
22
|
+
* - `"solid"` (default) — saturated brand fill with paired text color
|
|
23
|
+
* - `"outlined"` — transparent background, text === border
|
|
24
|
+
* - `"ghost"` — text only with hover background
|
|
25
|
+
*/
|
|
26
|
+
appearance?: ButtonAppearance;
|
|
27
|
+
/** Button size */
|
|
28
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
29
|
+
/** Button type for form submission */
|
|
30
|
+
type?: 'button' | 'submit' | 'reset';
|
|
31
|
+
/** Disable the button */
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
/** Pill-shaped button (rounded ends) */
|
|
34
|
+
pill?: boolean;
|
|
35
|
+
/** Action (icon-only square) */
|
|
36
|
+
action?: boolean;
|
|
37
|
+
/** Accessible label for screen readers */
|
|
38
|
+
label?: string;
|
|
39
|
+
/** Form field name for form submission */
|
|
40
|
+
name?: string;
|
|
41
|
+
/** Form field value for form submission */
|
|
42
|
+
value?: string;
|
|
43
|
+
/** Full-width button */
|
|
44
|
+
wide?: boolean;
|
|
45
|
+
/** Button content */
|
|
46
|
+
children?: React.ReactNode;
|
|
47
|
+
}
|
|
48
|
+
export declare const TyButton: React.ForwardRefExoticComponent<TyButtonProps & React.RefAttributes<HTMLElement>>;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=TyButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TyButton.d.ts","sourceRoot":"","sources":["../../src/components/TyButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,KAAK,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAC5F,KAAK,YAAY,GAAG,aAAa,GAAG,GAAG,aAAa,GAAG,GAAG,GAAG,aAAa,GAAG,CAAC;AAC9E,KAAK,gBAAgB,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAEvD,MAAM,WAAW,qBAAsB,SAAQ,KAAK,CAAC,aAAa;IAChE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IACrF,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAC9B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,YAAY,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAEtC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAE9B,kBAAkB;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAExC,sCAAsC;IACtC,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IAErC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,wCAAwC;IACxC,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,gCAAgC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,wBAAwB;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,eAAO,MAAM,QAAQ,mFAgFpB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
export const TyButton = React.forwardRef(({ children, type, appearance, disabled, pill, action, wide, label, name, value, onClick, ...props }, ref) => {
|
|
3
|
+
const elementRef = useRef(null);
|
|
4
|
+
// Imperatively attach the click listener so onClick reliably fires for the
|
|
5
|
+
// CustomEvent('click') that <ty-button> re-dispatches on its host (the
|
|
6
|
+
// inner <button> calls stopPropagation, so React's delegated onClick can
|
|
7
|
+
// miss it). Also handles type=submit by dispatching a synthetic submit.
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const element = elementRef.current;
|
|
10
|
+
if (!element)
|
|
11
|
+
return;
|
|
12
|
+
const handler = (event) => {
|
|
13
|
+
if (type === 'submit') {
|
|
14
|
+
const form = element.closest('form');
|
|
15
|
+
if (form) {
|
|
16
|
+
event.preventDefault();
|
|
17
|
+
event.stopPropagation();
|
|
18
|
+
form.dispatchEvent(new Event('submit', {
|
|
19
|
+
bubbles: true,
|
|
20
|
+
cancelable: true,
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (onClick) {
|
|
25
|
+
onClick(event);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
element.addEventListener('click', handler);
|
|
29
|
+
return () => {
|
|
30
|
+
element.removeEventListener('click', handler);
|
|
31
|
+
};
|
|
32
|
+
}, [type, onClick]);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (ref && elementRef.current) {
|
|
35
|
+
if (typeof ref === 'function') {
|
|
36
|
+
ref(elementRef.current);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
ref.current = elementRef.current;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}, [ref]);
|
|
43
|
+
const webComponentProps = {
|
|
44
|
+
...props,
|
|
45
|
+
ref: elementRef,
|
|
46
|
+
};
|
|
47
|
+
if (disabled)
|
|
48
|
+
webComponentProps.disabled = '';
|
|
49
|
+
if (pill)
|
|
50
|
+
webComponentProps.pill = '';
|
|
51
|
+
if (action)
|
|
52
|
+
webComponentProps.action = '';
|
|
53
|
+
if (wide)
|
|
54
|
+
webComponentProps.wide = '';
|
|
55
|
+
if (appearance)
|
|
56
|
+
webComponentProps.appearance = appearance;
|
|
57
|
+
if (type)
|
|
58
|
+
webComponentProps.type = type;
|
|
59
|
+
if (label)
|
|
60
|
+
webComponentProps.label = label;
|
|
61
|
+
if (name)
|
|
62
|
+
webComponentProps.name = name;
|
|
63
|
+
if (value)
|
|
64
|
+
webComponentProps.value = value;
|
|
65
|
+
return React.createElement('ty-button', webComponentProps, children);
|
|
66
|
+
});
|
|
67
|
+
TyButton.displayName = 'TyButton';
|
|
68
|
+
//# sourceMappingURL=TyButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TyButton.js","sourceRoot":"","sources":["../../src/components/TyButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAe,MAAM,OAAO,CAAC;AA8D9D,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CACtC,CAAC,EACC,QAAQ,EACR,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,KAAK,EACL,OAAO,EACP,GAAG,KAAK,EACT,EAAE,GAAG,EAAE,EAAE;IACR,MAAM,UAAU,GAAG,MAAM,CAAc,IAAI,CAAC,CAAC;IAE7C,2EAA2E;IAC3E,uEAAuE;IACvE,yEAAyE;IACzE,wEAAwE;IACxE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;QACnC,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,OAAO,GAAG,CAAC,KAAY,EAAE,EAAE;YAC/B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBACrC,IAAI,IAAI,EAAE,CAAC;oBACT,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,KAAK,CAAC,eAAe,EAAE,CAAC;oBACxB,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE;wBACrC,OAAO,EAAE,IAAI;wBACb,UAAU,EAAE,IAAI;qBACjB,CAAC,CAAC,CAAC;gBACN,CAAC;YACH,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAiD,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC,CAAC;QAEF,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3C,OAAO,GAAG,EAAE;YACV,OAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAEpB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,GAAG,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,OAAO,GAAG,KAAK,UAAU,EAAE,CAAC;gBAC9B,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEV,MAAM,iBAAiB,GAAwB;QAC7C,GAAG,KAAK;QACR,GAAG,EAAE,UAAU;KAChB,CAAC;IAEF,IAAI,QAAQ;QAAE,iBAAiB,CAAC,QAAQ,GAAG,EAAE,CAAC;IAC9C,IAAI,IAAI;QAAE,iBAAiB,CAAC,IAAI,GAAG,EAAE,CAAC;IACtC,IAAI,MAAM;QAAE,iBAAiB,CAAC,MAAM,GAAG,EAAE,CAAC;IAC1C,IAAI,IAAI;QAAE,iBAAiB,CAAC,IAAI,GAAG,EAAE,CAAC;IAEtC,IAAI,UAAU;QAAE,iBAAiB,CAAC,UAAU,GAAG,UAAU,CAAC;IAC1D,IAAI,IAAI;QAAE,iBAAiB,CAAC,IAAI,GAAG,IAAI,CAAC;IACxC,IAAI,KAAK;QAAE,iBAAiB,CAAC,KAAK,GAAG,KAAK,CAAC;IAC3C,IAAI,IAAI;QAAE,iBAAiB,CAAC,IAAI,GAAG,IAAI,CAAC;IACxC,IAAI,KAAK;QAAE,iBAAiB,CAAC,KAAK,GAAG,KAAK,CAAC;IAE3C,OAAO,KAAK,CAAC,aAAa,CACxB,WAAW,EACX,iBAAiB,EACjB,QAAQ,CACT,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface TyCalendarChangeEventDetail {
|
|
3
|
+
/** Selected month (1-12) */
|
|
4
|
+
month: number;
|
|
5
|
+
/** Selected year (4-digit) */
|
|
6
|
+
year: number;
|
|
7
|
+
/** Selected day (1-31) */
|
|
8
|
+
day: number;
|
|
9
|
+
/** Action that triggered the change: "select" */
|
|
10
|
+
action: 'select';
|
|
11
|
+
/** Source of the change: "day-click" */
|
|
12
|
+
source: 'day-click';
|
|
13
|
+
/** Complete day context from the calendar month */
|
|
14
|
+
dayContext: any;
|
|
15
|
+
}
|
|
16
|
+
export interface TyCalendarNavigateEventDetail {
|
|
17
|
+
/** Navigation target month (1-12) */
|
|
18
|
+
month: number;
|
|
19
|
+
/** Navigation target year (4-digit) */
|
|
20
|
+
year: number;
|
|
21
|
+
/** Action that triggered the navigation: "navigate" */
|
|
22
|
+
action: 'navigate';
|
|
23
|
+
/** Source of the change: "navigation" */
|
|
24
|
+
source: 'navigation';
|
|
25
|
+
}
|
|
26
|
+
export interface TyCalendarProps extends Omit<React.HTMLAttributes<HTMLElement>, 'onChange'> {
|
|
27
|
+
/** Selected year (4-digit) */
|
|
28
|
+
year?: number | string;
|
|
29
|
+
/** Selected month (1-12) */
|
|
30
|
+
month?: number | string;
|
|
31
|
+
/** Selected day (1-31) */
|
|
32
|
+
day?: number | string;
|
|
33
|
+
/** Show navigation controls */
|
|
34
|
+
showNavigation?: boolean;
|
|
35
|
+
/** Stateless mode - no internal state management */
|
|
36
|
+
stateless?: boolean;
|
|
37
|
+
/** Calendar size */
|
|
38
|
+
size?: 'sm' | 'md' | 'lg';
|
|
39
|
+
/** Locale for date formatting */
|
|
40
|
+
locale?: string;
|
|
41
|
+
/** Calendar width */
|
|
42
|
+
width?: string | number;
|
|
43
|
+
/** Minimum calendar width */
|
|
44
|
+
minWidth?: string | number;
|
|
45
|
+
/** Maximum calendar width */
|
|
46
|
+
maxWidth?: string | number;
|
|
47
|
+
/** Form field name for form submission */
|
|
48
|
+
name?: string;
|
|
49
|
+
/** Form value (ISO date string) */
|
|
50
|
+
value?: string;
|
|
51
|
+
/** Function to render custom day content */
|
|
52
|
+
dayContentFn?: (dayContext: any) => HTMLElement | string;
|
|
53
|
+
/** Function to determine day CSS classes */
|
|
54
|
+
dayClassesFn?: (dayContext: any) => string[];
|
|
55
|
+
/** Custom CSS injection for render functions */
|
|
56
|
+
customCSS?: string;
|
|
57
|
+
/** Callback when a date is selected */
|
|
58
|
+
onChange?: (event: CustomEvent<TyCalendarChangeEventDetail>) => void;
|
|
59
|
+
/** Callback when navigation changes month/year */
|
|
60
|
+
onNavigate?: (event: CustomEvent<TyCalendarNavigateEventDetail>) => void;
|
|
61
|
+
}
|
|
62
|
+
export declare const TyCalendar: React.ForwardRefExoticComponent<TyCalendarProps & React.RefAttributes<HTMLElement>>;
|
|
63
|
+
//# sourceMappingURL=TyCalendar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TyCalendar.d.ts","sourceRoot":"","sources":["../../src/components/TyCalendar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAG9D,MAAM,WAAW,2BAA2B;IAC1C,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,MAAM,EAAE,QAAQ,CAAC;IACjB,wCAAwC;IACxC,MAAM,EAAE,WAAW,CAAC;IACpB,mDAAmD;IACnD,UAAU,EAAE,GAAG,CAAC;CACjB;AAED,MAAM,WAAW,6BAA6B;IAC5C,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,EAAE,UAAU,CAAC;IACnB,yCAAyC;IACzC,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC;IAC1F,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEvB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAExB,0BAA0B;IAC1B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,oDAAoD;IACpD,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,oBAAoB;IACpB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAE1B,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAExB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAE3B,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAE3B,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,4CAA4C;IAC5C,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,WAAW,GAAG,MAAM,CAAC;IAEzD,4CAA4C;IAC5C,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,MAAM,EAAE,CAAC;IAE7C,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,2BAA2B,CAAC,KAAK,IAAI,CAAC;IAErE,kDAAkD;IAClD,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,6BAA6B,CAAC,KAAK,IAAI,CAAC;CAC1E;AAGD,eAAO,MAAM,UAAU,qFA8JtB,CAAC"}
|