` |
| `alert()` for validation | Toast notification (shadcn/ui `sonner`) |
| `` for XML output | `` with syntax highlighting (optional) + copy button |
| Direct `localStorage` | Storage abstraction via hook |
| JSZip CDN | `jszip` npm package |
### New Features in React Version
1. **Template presets per company**: Each company can have its own default categories and fields. Driven by company context.
2. **Save/load configurations**: Named configurations stored via storage abstraction. Users can maintain multiple XML schemas.
3. **Project tag linking**: When generating XML for a specific project, link the configuration to a project tag from the tag manager.
4. **Copy individual XPaths**: Click-to-copy on each XPath line, not just the whole block.
### File Structure
```
src/modules/xml-generator/
pages/
xml-generator-page.tsx -- Main page component
components/
xml-generator-form.tsx -- Namespace, root, mode controls
category-manager.tsx -- Category tabs/pills + CRUD
field-editor.tsx -- Textarea for field list
xml-preview.tsx -- XML output with copy/download
xpath-preview.tsx -- XPath output with copy
saved-configs-list.tsx -- Saved configuration browser
hooks/
use-xml-generator.ts -- XML generation logic
use-category-manager.ts -- Category state management
use-xml-export.ts -- Download/ZIP export
services/
zip-export-service.ts -- JSZip wrapper
utils/
sanitize-xml-name.ts -- Field name sanitization
generate-field-variants.ts -- Variant name generation
generate-xpaths.ts -- XPath string builder
data/
default-presets.ts -- Default category presets
types.ts -- Category, XmlGeneratorInput, etc.
```
---
## General Extraction Patterns
### DOM Manipulation to React State
| HTML/JS Pattern | React Equivalent |
|---|---|
| `document.getElementById('x').value` | `const [x, setX] = useState('')` + controlled input |
| `element.innerHTML = html` | JSX return with variables |
| `element.textContent = text` | `{text}` in JSX |
| `element.classList.toggle('active')` | Conditional className: `cn('pill', isActive && 'active')` |
| `element.style.backgroundColor = color` | `style={{ backgroundColor: color }}` or Tailwind class |
| `element.addEventListener('input', handler)` | `onChange={handler}` on element |
| `document.createElement('div')` | JSX element or `.map()` rendering |
| `parent.appendChild(child)` | Render in JSX, controlled by state array |
| `element.disabled = true` | `disabled={condition}` prop |
### Refs
Use `useRef` only when React state is insufficient:
- Measuring DOM element dimensions.
- Integrating with third-party DOM libraries.
- Storing mutable values that should not trigger re-render.
Do not use `useRef` as a replacement for `document.getElementById`. That pattern belongs in controlled component state.
### Storage
| HTML Pattern | React Equivalent |
|---|---|
| `localStorage.getItem('key')` | `storageAdapter.get('key')` |
| `localStorage.setItem('key', JSON.stringify(data))` | `storageAdapter.set('key', data)` |
| `JSON.parse(localStorage.getItem('key'))` | `storageAdapter.get('key')` (typed, handles parse errors) |
The storage abstraction (`src/core/storage/`) wraps localStorage with:
- Typed get/set.
- JSON serialization.
- Error handling (quota exceeded, parse failures).
- Key namespacing by module.
- Future: swap backend to IndexedDB or API without changing module code.
### Styling
| HTML Pattern | React Equivalent |
|---|---|
| Inline `style="color: #22B5AB"` | `className="text-teal-500"` or CSS variable |
| Tailwind CDN classes | Same Tailwind classes (compiled at build time, not CDN) |
| Raw CSS in `