Board
<gstock-board>
|
GstockBoard
Ejemplos
<gstock-board>
<gstock-board-item value="home">
<gstock-icon slot="prefix" name="home"></gstock-icon>
Inicio
</gstock-board-item>
<gstock-board-item value="users">
<gstock-icon slot="prefix" name="users"></gstock-icon>
Usuarios
</gstock-board-item>
<gstock-board-item value="settings">
<gstock-icon slot="prefix" name="settings"></gstock-icon>
Configuración
</gstock-board-item>
<gstock-board-item value="help">
<gstock-icon slot="prefix" name="help-circle"></gstock-icon>
Ayuda
</gstock-board-item>
</gstock-board>
Deshabilitado
Use el atributo disabled para deshabilitar la funcionalidad de arrastrar y soltar en toda la lista.
<gstock-board disabled>
<gstock-board-item value="item-1">Elemento 1 (Lista deshabilitada)</gstock-board-item>
<gstock-board-item value="item-2">Elemento 2 (Lista deshabilitada)</gstock-board-item>
<gstock-board-item value="item-3">Elemento 3 (Lista deshabilitada)</gstock-board-item>
</gstock-board>
Posicionamiento
Sistema inteligente que elimina posiciones duplicadas: cada elemento solo muestra líneas de inserción en posiciones únicas.
- Elementos 1-4: Solo muestran línea de inserción arriba
- Último elemento (5): Solo muestra línea de inserción abajo
- Resultado: Cada posición de inserción es única, sin redundancia
- Arrastra el elemento 4 sobre el elemento 2 → debería ir a posición 2
- Arrastra el elemento 1 al final → solo podrás soltarlo abajo del elemento 5
- Observa que no hay duplicidad de posiciones
<gstock-board id="no-redundancy-test">
<gstock-board-item value="item-1">
<span class="item red">1</span>
Primer elemento
</gstock-board-item>
<gstock-board-item value="item-2">
<span class="item orange">2</span>
Segundo elemento
</gstock-board-item>
<gstock-board-item value="item-3">
<span class="item yellow">3</span>
Tercer elemento
</gstock-board-item>
<gstock-board-item value="item-4">
<span class="item green">4</span>
Cuarto elemento
</gstock-board-item>
<gstock-board-item value="item-5">
<span class="item blue">5</span>
Quinto elemento (último)
</gstock-board-item>
</gstock-board>
<div class="note">
<strong>🎯 Lógica sin redundancia:</strong>
<ul class="note__list">
<li>
<strong>Elementos 1-4:</strong>
Solo muestran línea de inserción
<em>arriba</em>
</li>
<li>
<strong>Último elemento (5):</strong>
Solo muestra línea de inserción
<em>abajo</em>
</li>
<li>
<strong>Resultado:</strong>
Cada posición de inserción es única, sin redundancia
</li>
</ul>
</div>
<div class="order-block">
<strong>Orden actual:</strong>
<div id="current-order-no-redundancy" class="order-block__value"></div>
</div>
<div class="tips-block">
<strong>🧪 Pruebas sugeridas:</strong>
<ol class="tips-block__list">
<li>Arrastra el elemento 4 sobre el elemento 2 → debería ir a posición 2</li>
<li>Arrastra el elemento 1 al final → solo podrás soltarlo abajo del elemento 5</li>
<li>Observa que no hay duplicidad de posiciones</li>
</ol>
</div>
<script type="module">
const list = document.getElementById('no-redundancy-test');
const orderDisplay = document.getElementById('current-order-no-redundancy');
function updateOrderDisplay() {
const items = list.querySelectorAll('gstock-board-item');
const order = Array.from(items).map(item => item.getAttribute('value'));
orderDisplay.textContent = order.join(' → ');
}
// Initial display
updateOrderDisplay();
// Listen for sort events
list.addEventListener('gstock-sort', e => {
console.log('🔄 Sort sin redundancia:', e.detail);
updateOrderDisplay();
});
list.addEventListener('gstock-drag-start', e => {
console.log('🚀 Drag start:', e.detail.item.value);
});
list.addEventListener('gstock-drag-end', e => {
console.log('🏁 Drag end:', e.detail.item.value);
});
</script>
<style>
.item {
color: white;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-weight: bold;
margin-right: 0.5rem;
}
.item.red {
background: #ef4444;
}
.item.orange {
background: #f97316;
}
.item.yellow {
background: #eab308;
}
.item.green {
background: #22c55e;
}
.item.blue {
background: #3b82f6;
}
.note {
margin-top: 1rem;
padding: 1rem;
background: #fef3c7;
border-radius: 4px;
border-left: 4px solid #f59e0b;
}
.note__list {
margin: 0.5rem 0 0 1.5rem;
line-height: 1.6;
}
.order-block {
margin-top: 1rem;
padding: 1rem;
background: #f3f4f6;
border-radius: 4px;
}
.order-block__value {
font-family: monospace;
margin-top: 0.5rem;
font-weight: bold;
}
.tips-block {
margin-top: 1rem;
padding: 1rem;
background: #e0f2fe;
border-radius: 4px;
}
.tips-block__list {
margin: 0.5rem 0 0 1.5rem;
line-height: 1.6;
}
</style>
Lista Horizontal
Use el atributo orientation="horizontal" para crear una lista que se ordena horizontalmente.
<gstock-board orientation="horizontal">
<gstock-board-item value="item-1">Tab 1</gstock-board-item>
<gstock-board-item value="item-2">Tab 2</gstock-board-item>
<gstock-board-item value="item-3">Tab 3</gstock-board-item>
<gstock-board-item value="item-4">Tab 4</gstock-board-item>
</gstock-board>
<style>
gstock-board[orientation='horizontal'] {
display: flex;
gap: 0.5rem;
}
gstock-board[orientation='horizontal'] gstock-board-item {
min-width: 120px;
text-align: center;
}
</style>
Con Handle Personalizado
Use el atributo handle en los elementos para especificar un área específica como el controlador de arrastre.
<gstock-board>
<gstock-board-item value="item-1" handle=".drag-handle">
<gstock-icon slot="prefix" class="drag-handle" name="drag-indicator"></gstock-icon>
Elemento con handle personalizado 1
</gstock-board-item>
<gstock-board-item value="item-2" handle=".drag-handle">
<gstock-icon slot="prefix" class="drag-handle" name="drag-indicator"></gstock-icon>
Elemento con handle personalizado 2
</gstock-board-item>
<gstock-board-item value="item-3" handle=".drag-handle">
<gstock-icon slot="prefix" class="drag-handle" name="drag-indicator"></gstock-icon>
Elemento con handle personalizado 3
</gstock-board-item>
</gstock-board>
<style>
.drag-handle {
cursor: grab;
}
</style>
Eventos
La lista emite eventos cuando los elementos son reordenados, arrastramos elementos o terminamos de arrastrar.
Log de eventos:
<gstock-board>
<gstock-board-item value="item-1">Elemento 1</gstock-board-item>
<gstock-board-item value="item-2">Elemento 2</gstock-board-item>
<gstock-board-item value="item-3">Elemento 3</gstock-board-item>
<gstock-board-item value="item-4">Elemento 4</gstock-board-item>
</gstock-board>
<div class="board-events-section">
<h4>Log de eventos:</h4>
<div id="event-log"></div>
<gstock-button id="clear-log" size="small" variant="outline">Limpiar log</gstock-button>
</div>
<script type="module">
customElements.whenDefined('gstock-board').then(() => {
const board = document.querySelector('gstock-board');
const eventLog = document.getElementById('event-log');
const clearLogBtn = document.getElementById('clear-log');
function addLog(event, message) {
const timestamp = new Date().toLocaleTimeString();
const logEntry = document.createElement('div');
logEntry.className = 'log-entry';
logEntry.innerHTML = `<div><span class="timestamp">[${timestamp}]</span><strong>${event}</strong>:<span class="message">${message}</span></div>`;
eventLog.appendChild(logEntry);
eventLog.scrollTop = eventLog.scrollHeight;
}
board.addEventListener('gstock-sort-event', event => {
addLog(
'gstock-sort-event',
`Element "${event.detail.item.value}" moved from ${event.detail.from} to ${event.detail.to}\n`,
);
});
board.addEventListener('gstock-drag-start-event', event => {
addLog('gstock-drag-start-event', `Start drag from "${event.detail.item.value}"\n`);
});
board.addEventListener('gstock-drag-end-event', event => {
addLog('gstock-drag-end-event', `End drag from "${event.detail.item.value}"\n`);
});
clearLogBtn.addEventListener('click', () => {
eventLog.innerHTML = '';
});
});
</script>
<style>
.board-events-section {
margin-top: 1rem;
}
h4 {
margin: 0 0 0.5rem 0;
color: var(--gstock-legacy-color-grayscale-700);
}
#event-log {
border: 1px solid var(--gstock-legacy-color-grayscale-300);
border-radius: var(--gstock-border-radius-sm);
padding: 1rem;
height: 150px;
overflow-y: auto;
background-color: var(--gstock-legacy-color-grayscale-50);
font-family: var(--gstock-legacy-font-mono);
font-size: var(--gstock-legacy-font-size-sm);
margin-bottom: 0.5rem;
}
.log-entry {
margin-bottom: 0.25rem;
line-height: 1.4;
}
.timestamp {
color: var(--gstock-legacy-color-grayscale-500);
font-weight: 500;
}
.message {
color: var(--gstock-legacy-color-grayscale-700);
}
#event-log:empty::before {
color: var(--gstock-legacy-color-grayscale-400);
font-style: italic;
}
</style>
Accesibilidad
El componente incluye soporte completo para navegación por teclado usando las teclas de flecha, Space y Enter para reordenar elementos.
- Use Tab para navegar a la lista
- Use ↑ ↓ para navegar entre elementos
- Presione Space o Enter para entrar en modo de reordenamiento
- Use ↑ ↓ para mover el elemento seleccionado
- Presione Space o Enter para confirmar la nueva posición
- Presione Escape para cancelar el reordenamiento
<gstock-board>
<gstock-board-item value="item-1">
<gstock-icon slot="prefix" name="keyboard"></gstock-icon>
Use las teclas de flecha para navegar
</gstock-board-item>
<gstock-board-item value="item-2">
<gstock-icon slot="prefix" name="mouse-pointer"></gstock-icon>
Presione Space o Enter para seleccionar
</gstock-board-item>
<gstock-board-item value="item-3">
<gstock-icon slot="prefix" name="move"></gstock-icon>
Use las flechas para mover cuando esté seleccionado
</gstock-board-item>
<gstock-board-item value="item-4">
<gstock-icon slot="prefix" name="check"></gstock-icon>
Presione Space o Enter para confirmar la nueva posición
</gstock-board-item>
</gstock-board>
<div class="board-accessibility-info">
<strong>Instrucciones de accesibilidad:</strong>
<ul>
<li>
Use
<kbd>Tab</kbd>
para navegar a la lista
</li>
<li>
Use
<kbd>↑</kbd>
<kbd>↓</kbd>
para navegar entre elementos
</li>
<li>
Presione
<kbd>Space</kbd>
o
<kbd>Enter</kbd>
para entrar en modo de reordenamiento
</li>
<li>
Use
<kbd>↑</kbd>
<kbd>↓</kbd>
para mover el elemento seleccionado
</li>
<li>
Presione
<kbd>Space</kbd>
o
<kbd>Enter</kbd>
para confirmar la nueva posición
</li>
<li>
Presione
<kbd>Escape</kbd>
para cancelar el reordenamiento
</li>
</ul>
</div>
<style>
.board-accessibility-info {
margin-top: 1rem;
padding: 1rem;
background: #e3f2fd;
border-radius: 4px;
}
.board-accessibility-info ul {
margin: 0.5rem 0 0 1.5rem;
}
</style>
Depuración del Reordenamiento
Ejemplo para probar y depurar el funcionamiento del reordenamiento con feedback visual en tiempo real.
- Arrastra el elemento 3 antes del elemento 1
- Arrastra el elemento 5 entre el 2 y el 4
- Observa que el orden se actualiza correctamente abajo
<gstock-board id="test-list">
<gstock-board-item value="item-1">
<span class="board-debug-badge board-debug-badge--red">1</span>
Primer elemento
</gstock-board-item>
<gstock-board-item value="item-2">
<span class="board-debug-badge board-debug-badge--orange">2</span>
Segundo elemento
</gstock-board-item>
<gstock-board-item value="item-3">
<span class="board-debug-badge board-debug-badge--yellow">3</span>
Tercer elemento
</gstock-board-item>
<gstock-board-item value="item-4">
<span class="board-debug-badge board-debug-badge--green">4</span>
Cuarto elemento
</gstock-board-item>
<gstock-board-item value="item-5">
<span class="board-debug-badge board-debug-badge--blue">5</span>
Quinto elemento
</gstock-board-item>
</gstock-board>
<div class="board-debug-order">
<strong>Orden actual:</strong>
<div id="current-order" class="board-debug-order__value"></div>
</div>
<div class="board-debug-tips">
<strong>🧪 Prueba de reordenamiento:</strong>
<ol>
<li>Arrastra el elemento 3 antes del elemento 1</li>
<li>Arrastra el elemento 5 entre el 2 y el 4</li>
<li>Observa que el orden se actualiza correctamente abajo</li>
</ol>
</div>
<script type="module">
const list = document.getElementById('test-list');
const orderDisplay = document.getElementById('current-order');
function updateOrderDisplay() {
const items = list.querySelectorAll('gstock-board-item');
const order = Array.from(items).map(item => item.getAttribute('value'));
orderDisplay.textContent = order.join(' → ');
}
// Initial display
updateOrderDisplay();
// Listen for sort events
list.addEventListener('gstock-sort', e => {
console.log('Sort event:', e.detail);
updateOrderDisplay();
});
</script>
<style>
.board-debug-badge {
color: white;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-weight: bold;
margin-right: 0.5rem;
}
.board-debug-badge--red {
background: #f87171;
}
.board-debug-badge--orange {
background: #fb923c;
}
.board-debug-badge--yellow {
background: #fbbf24;
}
.board-debug-badge--green {
background: #34d399;
}
.board-debug-badge--blue {
background: #60a5fa;
}
.board-debug-order {
margin-top: 1rem;
padding: 1rem;
background: #f3f4f6;
border-radius: 4px;
}
.board-debug-order__value {
font-family: monospace;
margin-top: 0.5rem;
}
.board-debug-tips {
margin-top: 1rem;
padding: 1rem;
background: #fef3c7;
border-radius: 4px;
border-left: 4px solid #f59e0b;
}
.board-debug-tips ol {
margin: 0.5rem 0 0 1.5rem;
}
</style>