feat(17-02): repeater field and dependent dropdown states

- RepeaterField: rows with drag handle, index, titleFrom title, error chip,
  move up/down (buttons, ArrowUp/ArrowDown on the handle, native drag and
  drop), expand/collapse, remove (asks only for a row holding a value),
  add with nested defaults, maxItems counter, empty state, collapse all;
  every change edits form state only
- 422 row paths (content.3.answer) open the row, mark it and focus the
  nested control; the banner no longer repeats row messages
- DropdownField dependsOn: waiting, loading, not used, empty, loaded with
  depth indent, failed with retry; cached per sibling value, last request
  wins, a stale value is cleared after a sibling change and announced
- FormView provides form feedback (errors and notices by row path, the
  polite live region, its confirm dialog) and the options cache; FormGrid
  provides the sibling scope for repeater rows
- repeater.* and form.dependent_* phrase keys (en, pl), smoke specs, docs
This commit is contained in:
2026-10-12 16:08:23 +02:00
parent 4a5e896429
commit d3bf5d8f86
17 changed files with 1432 additions and 60 deletions

View File

@@ -103,6 +103,12 @@ form:
action_stale: This action no longer applies to this record. The page has been refreshed.
forbidden: You do not have permission to make this change. Nothing was saved.
dependent_invalid: Choose one of the listed options.
dependent_waiting: "Choose “:field” first"
dependent_not_used: Not used for this choice
dependent_empty: "No “:type” records yet. Add one first, or choose another type."
dependent_cleared: "“:field” was cleared because its options changed."
dependent_failed: The options could not be loaded.
dependent_retry: Retry loading options
relation:
add: Add
link: Link
@@ -356,6 +362,22 @@ richeditor:
repeater:
max_items: Remove items until there are at most :max.
min_items: Add items until there are at least :min.
add: Add item
empty: No items yet
empty_hint: "Use “:prompt” below to add the first one."
untitled: "Item :n"
count: "Items: :current of :max"
move: "Move: :title"
move_up: "Move up: :title"
move_down: "Move down: :title"
collapse: "Collapse: :title"
expand: "Expand: :title"
collapse_all: Collapse all
expand_all: Expand all
moved: ":title moved to position :position of :total."
remove: Remove item
remove_named: "Remove: :title"
remove_confirm: "Remove “:title”? The change is saved together with the record."
reorder:
stale: The records changed in the meantime. The list has been reloaded.
load_failed: The records could not be loaded. Refresh the page to try again.

View File

@@ -113,6 +113,12 @@ form:
action_stale: Ta akcja nie dotyczy już tego rekordu. Strona została odświeżona.
forbidden: Nie masz uprawnień do wprowadzenia tej zmiany. Nic nie zostało zapisane.
dependent_invalid: Wybierz jedną z dostępnych opcji.
dependent_waiting: "Najpierw wybierz pole „:field”"
dependent_not_used: Nie dotyczy tego wyboru
dependent_empty: "Brak rekordów typu „:type”. Najpierw dodaj rekord albo wybierz inny typ."
dependent_cleared: "Wyczyszczono pole „:field”, bo zmieniły się jego opcje."
dependent_failed: Nie udało się wczytać opcji.
dependent_retry: Ponów wczytywanie opcji
relation:
add: Dodaj
link: Dołącz
@@ -384,6 +390,22 @@ richeditor:
repeater:
max_items: Usuń pozycje, aby zostało ich najwyżej :max.
min_items: Dodaj pozycje, aby było ich co najmniej :min.
add: Dodaj pozycję
empty: Brak pozycji
empty_hint: "Użyj przycisku „:prompt” poniżej, aby dodać pierwszą."
untitled: "Pozycja :n"
count: "Pozycje: :current z :max"
move: "Przenieś: :title"
move_up: "Przenieś wyżej: :title"
move_down: "Przenieś niżej: :title"
collapse: "Zwiń: :title"
expand: "Rozwiń: :title"
collapse_all: Zwiń wszystkie
expand_all: Rozwiń wszystkie
moved: "Przeniesiono :title na pozycję :position z :total."
remove: Usuń pozycję
remove_named: "Usuń: :title"
remove_confirm: "Usunąć „:title”? Zmiana zostanie zapisana razem z rekordem."
reorder:
stale: Rekordy zmieniły się w międzyczasie. Lista została wczytana ponownie.
load_failed: Nie udało się wczytać rekordów. Odśwież stronę, aby spróbować ponownie.