@flood-md/agent 0.2.8 → 0.2.10
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/DESIGN.md +26 -4
- package/README.md +40 -1
- package/SKILL.md +46 -4
- package/dist/catalog.json +7136 -0
- package/dist/materials/component-accordion.md +42 -0
- package/dist/materials/component-alert-dialog.md +46 -0
- package/dist/materials/component-alert.md +41 -0
- package/dist/materials/component-aspect-ratio.md +36 -0
- package/dist/materials/component-avatar-group.md +39 -0
- package/dist/materials/component-avatar.md +40 -0
- package/dist/materials/component-badge.md +37 -0
- package/dist/materials/component-blockquote.md +35 -0
- package/dist/materials/component-breadcrumb.md +36 -0
- package/dist/materials/component-button-group.md +39 -0
- package/dist/materials/component-button.md +43 -0
- package/dist/materials/component-calendar.md +59 -0
- package/dist/materials/component-card.md +46 -0
- package/dist/materials/component-center.md +39 -0
- package/dist/materials/component-character-count.md +42 -0
- package/dist/materials/component-check-card.md +39 -0
- package/dist/materials/component-checkbox-group.md +48 -0
- package/dist/materials/component-checkbox.md +37 -0
- package/dist/materials/component-code-snippet.md +37 -0
- package/dist/materials/component-collapsible.md +40 -0
- package/dist/materials/component-color-picker.md +49 -0
- package/dist/materials/component-color-swatch.md +35 -0
- package/dist/materials/component-combobox.md +50 -0
- package/dist/materials/component-command-list.md +48 -0
- package/dist/materials/component-container.md +36 -0
- package/dist/materials/component-context-menu.md +43 -0
- package/dist/materials/component-copy-button.md +42 -0
- package/dist/materials/component-data-list-item.md +40 -0
- package/dist/materials/component-data-list.md +38 -0
- package/dist/materials/component-data-table.md +58 -0
- package/dist/materials/component-date-field.md +57 -0
- package/dist/materials/component-date-picker.md +66 -0
- package/dist/materials/component-date-range-field.md +62 -0
- package/dist/materials/component-date-range-picker.md +72 -0
- package/dist/materials/component-date-time-picker.md +60 -0
- package/dist/materials/component-date-time-range-picker.md +66 -0
- package/dist/materials/component-description-list.md +42 -0
- package/dist/materials/component-dialog.md +45 -0
- package/dist/materials/component-divider.md +37 -0
- package/dist/materials/component-drawer.md +50 -0
- package/dist/materials/component-dropzone.md +45 -0
- package/dist/materials/component-editable.md +57 -0
- package/dist/materials/component-empty-state.md +41 -0
- package/dist/materials/component-error-summary.md +40 -0
- package/dist/materials/component-field.md +46 -0
- package/dist/materials/component-fieldset.md +46 -0
- package/dist/materials/component-figure.md +36 -0
- package/dist/materials/component-file-input.md +45 -0
- package/dist/materials/component-file-item.md +48 -0
- package/dist/materials/component-file-list.md +39 -0
- package/dist/materials/component-file-meta.md +36 -0
- package/dist/materials/component-flood-root.md +33 -0
- package/dist/materials/component-grid.md +38 -0
- package/dist/materials/component-heading.md +38 -0
- package/dist/materials/component-hover-card.md +48 -0
- package/dist/materials/component-icon-button.md +41 -0
- package/dist/materials/component-icon-slot.md +37 -0
- package/dist/materials/component-image-preview.md +50 -0
- package/dist/materials/component-image.md +37 -0
- package/dist/materials/component-inline-code.md +36 -0
- package/dist/materials/component-inline.md +39 -0
- package/dist/materials/component-input-group.md +43 -0
- package/dist/materials/component-input.md +39 -0
- package/dist/materials/component-kbd.md +34 -0
- package/dist/materials/component-label.md +37 -0
- package/dist/materials/component-link.md +35 -0
- package/dist/materials/component-list-box.md +57 -0
- package/dist/materials/component-list.md +40 -0
- package/dist/materials/component-menu.md +54 -0
- package/dist/materials/component-meter.md +43 -0
- package/dist/materials/component-metric.md +39 -0
- package/dist/materials/component-multi-select.md +52 -0
- package/dist/materials/component-navigation-list.md +38 -0
- package/dist/materials/component-navigation-tree.md +43 -0
- package/dist/materials/component-number-input.md +47 -0
- package/dist/materials/component-pagination.md +44 -0
- package/dist/materials/component-password-input.md +43 -0
- package/dist/materials/component-pin-input.md +45 -0
- package/dist/materials/component-popover.md +47 -0
- package/dist/materials/component-progress.md +42 -0
- package/dist/materials/component-radio-card.md +43 -0
- package/dist/materials/component-radio-group.md +49 -0
- package/dist/materials/component-radio.md +39 -0
- package/dist/materials/component-range-calendar.md +58 -0
- package/dist/materials/component-rating.md +46 -0
- package/dist/materials/component-resizable-panels.md +48 -0
- package/dist/materials/component-scroll-area.md +42 -0
- package/dist/materials/component-search-input.md +40 -0
- package/dist/materials/component-section.md +42 -0
- package/dist/materials/component-segmented-control.md +51 -0
- package/dist/materials/component-select.md +45 -0
- package/dist/materials/component-skeleton.md +42 -0
- package/dist/materials/component-skip-link.md +37 -0
- package/dist/materials/component-slider.md +51 -0
- package/dist/materials/component-spinner.md +37 -0
- package/dist/materials/component-split.md +40 -0
- package/dist/materials/component-stack.md +37 -0
- package/dist/materials/component-status-indicator.md +38 -0
- package/dist/materials/component-steps.md +40 -0
- package/dist/materials/component-surface.md +37 -0
- package/dist/materials/component-switch.md +35 -0
- package/dist/materials/component-table.md +46 -0
- package/dist/materials/component-tabs.md +43 -0
- package/dist/materials/component-tag-input.md +46 -0
- package/dist/materials/component-tag.md +40 -0
- package/dist/materials/component-text.md +39 -0
- package/dist/materials/component-textarea.md +38 -0
- package/dist/materials/component-time-field.md +56 -0
- package/dist/materials/component-time-picker.md +60 -0
- package/dist/materials/component-timeline.md +38 -0
- package/dist/materials/component-toast-region.md +42 -0
- package/dist/materials/component-toggle-group.md +44 -0
- package/dist/materials/component-toggle.md +39 -0
- package/dist/materials/component-toolbar.md +42 -0
- package/dist/materials/component-tooltip.md +40 -0
- package/dist/materials/component-tree-select.md +56 -0
- package/dist/materials/component-tree.md +52 -0
- package/dist/materials/component-upload-item.md +52 -0
- package/dist/materials/component-upload-list.md +40 -0
- package/dist/materials/component-visually-hidden.md +37 -0
- package/dist/materials/guide-agent-knowledge.md +88 -0
- package/dist/materials/guide-agents.md +96 -0
- package/dist/materials/guide-faq.md +84 -0
- package/dist/materials/guide-foundations.md +232 -0
- package/dist/materials/guide-installation.md +79 -0
- package/dist/materials/guide-interface-content.md +76 -0
- package/dist/materials/guide-introduction.md +40 -0
- package/dist/materials/guide-layout.md +193 -0
- package/dist/materials/guide-privacy.md +23 -0
- package/dist/materials/guide-project-ui.md +127 -0
- package/dist/materials/guide-skills.md +108 -0
- package/dist/materials/guide-theming.md +73 -0
- package/dist/materials/recipe-command-palette.md +66 -0
- package/dist/materials/recipe-filter-bar.md +59 -0
- package/dist/materials/recipe-form-submission.md +39 -0
- package/dist/materials/recipe-grouped-form.md +66 -0
- package/dist/materials/recipe-select-all.md +31 -0
- package/dist/materials/recipe-split-button.md +26 -0
- package/dist/materials/recipe-table-bulk-actions.md +88 -0
- package/dist/materials/recipe-workspace-review.md +134 -0
- package/dist/materials/token-sys.color.accent.content.json +41 -0
- package/dist/materials/token-sys.color.action.danger.content.json +42 -0
- package/dist/materials/token-sys.color.action.ghost.content.json +41 -0
- package/dist/materials/token-sys.color.action.ghost.disabled-content.json +41 -0
- package/dist/materials/token-sys.color.action.ghost.disabled.json +41 -0
- package/dist/materials/token-sys.color.action.ghost.hover.json +41 -0
- package/dist/materials/token-sys.color.action.ghost.pressed.json +41 -0
- package/dist/materials/token-sys.color.action.ghost.rest.json +41 -0
- package/dist/materials/token-sys.color.action.on-surface.content.json +39 -0
- package/dist/materials/token-sys.color.action.on-surface.disabled-content.json +39 -0
- package/dist/materials/token-sys.color.action.on-surface.disabled.json +39 -0
- package/dist/materials/token-sys.color.action.on-surface.hover.json +39 -0
- package/dist/materials/token-sys.color.action.on-surface.pressed.json +39 -0
- package/dist/materials/token-sys.color.action.on-surface.rest.json +39 -0
- package/dist/materials/token-sys.color.action.primary.content.json +39 -0
- package/dist/materials/token-sys.color.action.primary.disabled-content.json +39 -0
- package/dist/materials/token-sys.color.action.primary.disabled.json +39 -0
- package/dist/materials/token-sys.color.action.primary.hover.json +39 -0
- package/dist/materials/token-sys.color.action.primary.pressed.json +39 -0
- package/dist/materials/token-sys.color.action.primary.rest.json +39 -0
- package/dist/materials/token-sys.color.action.subtle.content.json +39 -0
- package/dist/materials/token-sys.color.action.subtle.disabled-content.json +39 -0
- package/dist/materials/token-sys.color.action.subtle.disabled.json +39 -0
- package/dist/materials/token-sys.color.action.subtle.hover.json +39 -0
- package/dist/materials/token-sys.color.action.subtle.pressed.json +39 -0
- package/dist/materials/token-sys.color.action.subtle.rest.json +39 -0
- package/dist/materials/token-sys.color.border.decorative.json +42 -0
- package/dist/materials/token-sys.color.border.default.json +39 -0
- package/dist/materials/token-sys.color.border.floating.json +39 -0
- package/dist/materials/token-sys.color.border.strong.json +39 -0
- package/dist/materials/token-sys.color.content.default.json +41 -0
- package/dist/materials/token-sys.color.content.helper.json +39 -0
- package/dist/materials/token-sys.color.content.subtle.json +43 -0
- package/dist/materials/token-sys.color.divider.decorative.json +41 -0
- package/dist/materials/token-sys.color.feedback.error.json +39 -0
- package/dist/materials/token-sys.color.feedback.info.json +39 -0
- package/dist/materials/token-sys.color.feedback.success.json +39 -0
- package/dist/materials/token-sys.color.feedback.warning.json +39 -0
- package/dist/materials/token-sys.color.field.background.json +39 -0
- package/dist/materials/token-sys.color.field.border.json +39 -0
- package/dist/materials/token-sys.color.field.boundary.json +39 -0
- package/dist/materials/token-sys.color.field.content.json +39 -0
- package/dist/materials/token-sys.color.field.disabled-content.json +39 -0
- package/dist/materials/token-sys.color.field.disabled.json +39 -0
- package/dist/materials/token-sys.color.field.placeholder.json +39 -0
- package/dist/materials/token-sys.color.focus.ring.json +39 -0
- package/dist/materials/token-sys.color.indicator.accent.json +39 -0
- package/dist/materials/token-sys.color.indicator.fill.json +39 -0
- package/dist/materials/token-sys.color.indicator.track.json +39 -0
- package/dist/materials/token-sys.color.loading.placeholder.json +42 -0
- package/dist/materials/token-sys.color.scrollbar.thumb-hover.json +39 -0
- package/dist/materials/token-sys.color.scrollbar.thumb.json +39 -0
- package/dist/materials/token-sys.color.selection.background.json +39 -0
- package/dist/materials/token-sys.color.selection.content.json +39 -0
- package/dist/materials/token-sys.color.selection.floating.json +39 -0
- package/dist/materials/token-sys.color.shadow.floating.json +39 -0
- package/dist/materials/token-sys.color.surface.canvas.json +39 -0
- package/dist/materials/token-sys.color.surface.default.json +39 -0
- package/dist/materials/token-sys.color.surface.floating-translucent.json +39 -0
- package/dist/materials/token-sys.color.surface.floating.json +39 -0
- package/dist/materials/token-sys.color.surface.overlay.json +39 -0
- package/dist/materials/token-sys.color.surface.raised.json +39 -0
- package/dist/materials/token-sys.control.2xl.gap.json +34 -0
- package/dist/materials/token-sys.control.2xl.height.json +34 -0
- package/dist/materials/token-sys.control.2xl.icon-size.json +34 -0
- package/dist/materials/token-sys.control.2xl.line-height.json +31 -0
- package/dist/materials/token-sys.control.2xl.padding-inline.json +34 -0
- package/dist/materials/token-sys.control.2xl.text-size.json +34 -0
- package/dist/materials/token-sys.control.2xs.gap.json +34 -0
- package/dist/materials/token-sys.control.2xs.height.json +34 -0
- package/dist/materials/token-sys.control.2xs.icon-size.json +34 -0
- package/dist/materials/token-sys.control.2xs.line-height.json +31 -0
- package/dist/materials/token-sys.control.2xs.padding-inline.json +34 -0
- package/dist/materials/token-sys.control.2xs.text-size.json +34 -0
- package/dist/materials/token-sys.control.lg.gap.json +34 -0
- package/dist/materials/token-sys.control.lg.height.json +34 -0
- package/dist/materials/token-sys.control.lg.icon-size.json +34 -0
- package/dist/materials/token-sys.control.lg.line-height.json +31 -0
- package/dist/materials/token-sys.control.lg.padding-inline.json +34 -0
- package/dist/materials/token-sys.control.lg.text-size.json +34 -0
- package/dist/materials/token-sys.control.md.gap.json +34 -0
- package/dist/materials/token-sys.control.md.height.json +34 -0
- package/dist/materials/token-sys.control.md.icon-size.json +34 -0
- package/dist/materials/token-sys.control.md.line-height.json +31 -0
- package/dist/materials/token-sys.control.md.padding-inline.json +34 -0
- package/dist/materials/token-sys.control.md.text-size.json +34 -0
- package/dist/materials/token-sys.control.sm.gap.json +34 -0
- package/dist/materials/token-sys.control.sm.height.json +34 -0
- package/dist/materials/token-sys.control.sm.icon-size.json +34 -0
- package/dist/materials/token-sys.control.sm.line-height.json +31 -0
- package/dist/materials/token-sys.control.sm.padding-inline.json +34 -0
- package/dist/materials/token-sys.control.sm.text-size.json +34 -0
- package/dist/materials/token-sys.control.xl.gap.json +34 -0
- package/dist/materials/token-sys.control.xl.height.json +34 -0
- package/dist/materials/token-sys.control.xl.icon-size.json +34 -0
- package/dist/materials/token-sys.control.xl.line-height.json +31 -0
- package/dist/materials/token-sys.control.xl.padding-inline.json +34 -0
- package/dist/materials/token-sys.control.xl.text-size.json +34 -0
- package/dist/materials/token-sys.control.xs.gap.json +34 -0
- package/dist/materials/token-sys.control.xs.height.json +34 -0
- package/dist/materials/token-sys.control.xs.icon-size.json +34 -0
- package/dist/materials/token-sys.control.xs.line-height.json +31 -0
- package/dist/materials/token-sys.control.xs.padding-inline.json +34 -0
- package/dist/materials/token-sys.control.xs.text-size.json +34 -0
- package/dist/materials/token-sys.effect.floating.blur.json +34 -0
- package/dist/materials/token-sys.effect.floating.saturation.json +31 -0
- package/dist/materials/token-sys.effect.floating.shadow-blur.json +34 -0
- package/dist/materials/token-sys.effect.floating.shadow-offset.json +34 -0
- package/dist/materials/token-sys.focus.offset.json +34 -0
- package/dist/materials/token-sys.focus.width.json +34 -0
- package/dist/materials/token-sys.font.mono.json +36 -0
- package/dist/materials/token-sys.font.sans.json +35 -0
- package/dist/materials/token-sys.layer.base.json +31 -0
- package/dist/materials/token-sys.layer.modal.json +31 -0
- package/dist/materials/token-sys.layer.popover.json +31 -0
- package/dist/materials/token-sys.layer.sticky.json +31 -0
- package/dist/materials/token-sys.layer.toast.json +31 -0
- package/dist/materials/token-sys.motion.duration-fast.json +34 -0
- package/dist/materials/token-sys.motion.duration-normal.json +34 -0
- package/dist/materials/token-sys.motion.duration-reduced.json +34 -0
- package/dist/materials/token-sys.motion.easing.json +36 -0
- package/dist/materials/token-sys.radius.action.json +34 -0
- package/dist/materials/token-sys.radius.block.json +34 -0
- package/dist/materials/token-sys.radius.field.json +34 -0
- package/dist/materials/token-sys.radius.indicator.json +34 -0
- package/dist/materials/token-sys.radius.surface.json +34 -0
- package/dist/materials/token-sys.scrollbar.inset.json +34 -0
- package/dist/materials/token-sys.scrollbar.min-thumb.json +34 -0
- package/dist/materials/token-sys.scrollbar.size.json +34 -0
- package/dist/materials/token-sys.size.choice.json +34 -0
- package/dist/materials/token-sys.size.container.lg.json +37 -0
- package/dist/materials/token-sys.size.container.md.json +37 -0
- package/dist/materials/token-sys.size.container.sm.json +37 -0
- package/dist/materials/token-sys.size.grid.min-item.json +37 -0
- package/dist/materials/token-sys.size.indicator.lg.json +34 -0
- package/dist/materials/token-sys.size.indicator.md.json +34 -0
- package/dist/materials/token-sys.size.indicator.sm.json +34 -0
- package/dist/materials/token-sys.size.keycap.lg.json +34 -0
- package/dist/materials/token-sys.size.keycap.md.json +34 -0
- package/dist/materials/token-sys.size.keycap.sm.json +34 -0
- package/dist/materials/token-sys.size.switch-height.json +34 -0
- package/dist/materials/token-sys.size.switch-thumb.json +34 -0
- package/dist/materials/token-sys.size.switch-width.json +34 -0
- package/dist/materials/token-sys.size.touch.json +34 -0
- package/dist/materials/token-sys.space.0.json +34 -0
- package/dist/materials/token-sys.space.1.json +34 -0
- package/dist/materials/token-sys.space.12.json +34 -0
- package/dist/materials/token-sys.space.2.json +34 -0
- package/dist/materials/token-sys.space.3.json +34 -0
- package/dist/materials/token-sys.space.4.json +34 -0
- package/dist/materials/token-sys.space.6.json +34 -0
- package/dist/materials/token-sys.space.8.json +34 -0
- package/dist/materials/token-sys.stroke.width.json +34 -0
- package/dist/materials/token-sys.type.body.line-height.json +31 -0
- package/dist/materials/token-sys.type.body.size.json +34 -0
- package/dist/materials/token-sys.type.body.tracking.json +34 -0
- package/dist/materials/token-sys.type.body.weight.json +31 -0
- package/dist/materials/token-sys.type.compact.line-height.json +31 -0
- package/dist/materials/token-sys.type.compact.size.json +34 -0
- package/dist/materials/token-sys.type.compact.tracking.json +34 -0
- package/dist/materials/token-sys.type.compact.weight.json +31 -0
- package/dist/materials/token-sys.type.control.line-height.json +31 -0
- package/dist/materials/token-sys.type.control.size.json +34 -0
- package/dist/materials/token-sys.type.control.tracking.json +34 -0
- package/dist/materials/token-sys.type.control.weight.json +31 -0
- package/dist/materials/token-sys.type.dialog-title.line-height.json +33 -0
- package/dist/materials/token-sys.type.dialog-title.size.json +36 -0
- package/dist/materials/token-sys.type.dialog-title.tracking.json +36 -0
- package/dist/materials/token-sys.type.dialog-title.weight.json +33 -0
- package/dist/materials/token-sys.type.display.line-height.json +31 -0
- package/dist/materials/token-sys.type.display.size.json +34 -0
- package/dist/materials/token-sys.type.display.tracking.json +34 -0
- package/dist/materials/token-sys.type.display.weight.json +31 -0
- package/dist/materials/token-sys.type.field-label.line-height.json +33 -0
- package/dist/materials/token-sys.type.field-label.size.json +36 -0
- package/dist/materials/token-sys.type.field-label.tracking.json +36 -0
- package/dist/materials/token-sys.type.field-label.weight.json +33 -0
- package/dist/materials/token-sys.type.group-title.line-height.json +33 -0
- package/dist/materials/token-sys.type.group-title.size.json +36 -0
- package/dist/materials/token-sys.type.group-title.tracking.json +36 -0
- package/dist/materials/token-sys.type.group-title.weight.json +33 -0
- package/dist/materials/token-sys.type.helper.line-height.json +31 -0
- package/dist/materials/token-sys.type.helper.size.json +34 -0
- package/dist/materials/token-sys.type.helper.tracking.json +34 -0
- package/dist/materials/token-sys.type.helper.weight.json +31 -0
- package/dist/materials/token-sys.type.label.line-height.json +31 -0
- package/dist/materials/token-sys.type.label.size.json +34 -0
- package/dist/materials/token-sys.type.label.tracking.json +34 -0
- package/dist/materials/token-sys.type.label.weight.json +31 -0
- package/dist/materials/token-sys.type.large.line-height.json +31 -0
- package/dist/materials/token-sys.type.large.size.json +34 -0
- package/dist/materials/token-sys.type.large.tracking.json +34 -0
- package/dist/materials/token-sys.type.large.weight.json +31 -0
- package/dist/materials/token-sys.type.lead.line-height.json +31 -0
- package/dist/materials/token-sys.type.lead.size.json +34 -0
- package/dist/materials/token-sys.type.lead.tracking.json +34 -0
- package/dist/materials/token-sys.type.lead.weight.json +31 -0
- package/dist/materials/token-sys.type.page.line-height.json +31 -0
- package/dist/materials/token-sys.type.page.size.json +34 -0
- package/dist/materials/token-sys.type.page.tracking.json +34 -0
- package/dist/materials/token-sys.type.page.weight.json +31 -0
- package/dist/materials/token-sys.type.section.line-height.json +31 -0
- package/dist/materials/token-sys.type.section.size.json +34 -0
- package/dist/materials/token-sys.type.section.tracking.json +34 -0
- package/dist/materials/token-sys.type.section.weight.json +31 -0
- package/knowledge.json +409 -0
- package/lib/index.d.ts +33 -0
- package/lib/index.mjs +144 -0
- package/lib/inspect.d.ts +12 -0
- package/lib/inspect.mjs +187 -0
- package/manifest.json +91 -1
- package/package.json +9 -1
- package/references/flood-accessibility/SKILL.md +40 -0
- package/references/flood-composition/SKILL.md +30 -0
- package/references/flood-data-display/SKILL.md +69 -0
- package/references/flood-feedback/SKILL.md +58 -0
- package/references/flood-forms/SKILL.md +94 -0
- package/references/flood-foundations/SKILL.md +44 -0
- package/references/flood-hierarchy/SKILL.md +87 -0
- package/references/flood-interface-content/SKILL.md +142 -0
- package/references/flood-navigation/SKILL.md +35 -0
- package/references/flood-overlays/SKILL.md +52 -0
- package/references/flood-records/SKILL.md +108 -0
- package/references/flood-spacing/SKILL.md +62 -0
- package/references/flood-verification/SKILL.md +99 -0
- package/references/interface-content-examples.md +47 -0
- package/references/knowledge.md +49 -0
- package/references/record-decisions.md +25 -0
- package/references/rendered-review.md +97 -0
- package/references/routing.md +1 -0
- package/rules.json +454 -2
- package/workflows.json +152 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Customization · 0.2.5
|
|
2
|
+
|
|
3
|
+
Start with the neutral dark foundations profile. `FloodRoot` selects it locally;
|
|
4
|
+
version 0.2.5 does not provide a light foundations profile or a theme editor.
|
|
5
|
+
Use component props for everyday variations and semantic CSS roles for project
|
|
6
|
+
styling. Keep typography, spacing and finite geometry in relative units.
|
|
7
|
+
|
|
8
|
+
## Scope your overrides
|
|
9
|
+
|
|
10
|
+
Import Flood before your own stylesheet and put a class on the same root:
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import "@flood-md/react/styles.css";
|
|
14
|
+
import "./theme.css";
|
|
15
|
+
import { FloodRoot, Input, Field } from "@flood-md/react";
|
|
16
|
+
|
|
17
|
+
export function App() {
|
|
18
|
+
return (
|
|
19
|
+
<FloodRoot className="my-app">
|
|
20
|
+
<Field label="Workspace name">
|
|
21
|
+
{(props) => <Input {...props} />}
|
|
22
|
+
</Field>
|
|
23
|
+
</FloodRoot>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This example uses Field's function child; in Next.js put it in a client component.
|
|
29
|
+
Import global styles once from the root layout.
|
|
30
|
+
|
|
31
|
+
```css
|
|
32
|
+
/* theme.css: an opt-in project override, not a new Flood default. */
|
|
33
|
+
.my-app[data-flood-foundations="neutral"][data-flood-theme="dark"] {
|
|
34
|
+
--flood-sys-radius-field: 1.25rem;
|
|
35
|
+
--flood-sys-type-body-size: 1rem;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The selector targets the same scope and has enough specificity to override the
|
|
40
|
+
profile declarations. A custom property set on an ancestor may be replaced by a
|
|
41
|
+
profile declaration on FloodRoot. Inspect computed values in the actual host app.
|
|
42
|
+
|
|
43
|
+
## Choose semantic roles
|
|
44
|
+
|
|
45
|
+
Use public `sys.*` roles, exposed in CSS as `--flood-sys-*`. Families include
|
|
46
|
+
surface, content, actions, fields, feedback, focus, typography, spacing, radii,
|
|
47
|
+
control sizes and motion. The [foundations guide](foundations.md) explains the
|
|
48
|
+
typed lookup, manifest and scope rules.
|
|
49
|
+
|
|
50
|
+
Reference (`ref.*`) values are internal building blocks. Their IDs are not a
|
|
51
|
+
public customization contract. Existing props such as Button size/variant,
|
|
52
|
+
Input controlSize and Surface elevation handle many variations without overrides.
|
|
53
|
+
|
|
54
|
+
## Preserve useful distinctions
|
|
55
|
+
|
|
56
|
+
Keep primary text readable, secondary text appropriate for its size, and necessary
|
|
57
|
+
field boundaries distinct from quiet decorative borders. Preserve visible keyboard
|
|
58
|
+
focus and native control behavior. Check text with WCAG and APCA guidance in the
|
|
59
|
+
actual composition; a token name or a screenshot does not certify accessibility.
|
|
60
|
+
Test narrow layouts, increased root text size, forced colors and reduced motion.
|
|
61
|
+
|
|
62
|
+
## Legacy themes outside FloodRoot
|
|
63
|
+
|
|
64
|
+
Earlier controls outside FloodRoot retain the legacy `--flood-*` variables and
|
|
65
|
+
OS-following light/dark behavior. Explicit `data-flood-theme="light"` or `"dark"`
|
|
66
|
+
selects that legacy theme. These variables do not configure the new foundations
|
|
67
|
+
profile, and changing FloodRoot's theme attribute does not create a supported
|
|
68
|
+
light foundations theme.
|
|
69
|
+
|
|
70
|
+
For an existing 0.1.x project, follow its installed guide and compare the
|
|
71
|
+
[migration instructions](installation.md#updates-from-011) before adopting
|
|
72
|
+
FloodRoot. Keep the exact Flood package versions aligned and verify your app
|
|
73
|
+
after changing CSS scope or customization.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Command palette
|
|
2
|
+
|
|
3
|
+
Compose Dialog and CommandList when commands need a modal search surface. Keep
|
|
4
|
+
routing, permissions and business actions in your application. This is a project
|
|
5
|
+
recipe using the 0.2.7 source API, not another package export.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
"use client";
|
|
9
|
+
|
|
10
|
+
import { useState } from "react";
|
|
11
|
+
import { Button, CommandList, Dialog, FloodRoot } from "@flood-md/react";
|
|
12
|
+
|
|
13
|
+
export function CommandPalette({ onCommand }: { onCommand: (id: string) => void }) {
|
|
14
|
+
const [open, setOpen] = useState(false);
|
|
15
|
+
const [query, setQuery] = useState("");
|
|
16
|
+
|
|
17
|
+
function changeOpen(next: boolean) {
|
|
18
|
+
if (next) setQuery("");
|
|
19
|
+
setOpen(next);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<FloodRoot>
|
|
24
|
+
<Dialog
|
|
25
|
+
title="Commands"
|
|
26
|
+
open={open}
|
|
27
|
+
onOpenChange={changeOpen}
|
|
28
|
+
trigger={props => <Button {...props} variant="subtle">Commands</Button>}
|
|
29
|
+
>
|
|
30
|
+
<CommandList
|
|
31
|
+
label="Search commands"
|
|
32
|
+
hideLabel
|
|
33
|
+
query={query}
|
|
34
|
+
onQueryChange={setQuery}
|
|
35
|
+
items={[
|
|
36
|
+
{ id: "new-project", label: "New project", group: "Projects", keywords: ["create"] },
|
|
37
|
+
{ id: "recent-projects", label: "Recent projects", group: "Projects" },
|
|
38
|
+
{ id: "settings", label: "Open settings", group: "Workspace" },
|
|
39
|
+
]}
|
|
40
|
+
onAction={id => {
|
|
41
|
+
changeOpen(false);
|
|
42
|
+
onCommand(id);
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
45
|
+
</Dialog>
|
|
46
|
+
</FloodRoot>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Import the Flood stylesheet once at your application entry. If this component
|
|
52
|
+
already lives inside FloodRoot, reuse that scope instead of adding another one.
|
|
53
|
+
|
|
54
|
+
Dialog owns modal focus, Escape, outside dismissal and trigger focus restoration.
|
|
55
|
+
CommandList owns filtering, grouped results and keyboard invocation. Opening the
|
|
56
|
+
palette clears its query; closing it does not execute a command. Escape stays
|
|
57
|
+
available to Dialog rather than being consumed by the search control.
|
|
58
|
+
|
|
59
|
+
`onCommand` identifies a host-owned action. It is not awaited: keep saving state,
|
|
60
|
+
errors and navigation in your application. An action may move focus to its own
|
|
61
|
+
destination; the layer should preserve that deliberate focus change.
|
|
62
|
+
|
|
63
|
+
Add a global shortcut only at the application boundary, with your own editing,
|
|
64
|
+
permission and nested-layer policy. Do not display a shortcut hint until that
|
|
65
|
+
shortcut actually works. No shortcut, router, fuzzy-ranking service or command
|
|
66
|
+
permission engine is installed by this recipe.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Filter bar
|
|
2
|
+
|
|
3
|
+
Compose existing Field, SearchInput, Select and Button. Filtering belongs to the
|
|
4
|
+
host collection, not to DataTable. This recipe filters the full local data set
|
|
5
|
+
before handing it to the table and resets page and selection when filters change.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
"use client";
|
|
9
|
+
import {useState} from "react";
|
|
10
|
+
import {Button, DataTable, Field, Inline, SearchInput, Select, Stack} from "@flood-md/react";
|
|
11
|
+
|
|
12
|
+
const projects = [
|
|
13
|
+
{id: "design", name: "Design system", status: "Active", members: 12},
|
|
14
|
+
{id: "website", name: "Website", status: "Active", members: 4},
|
|
15
|
+
{id: "research", name: "Research", status: "Draft", members: 2},
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export function ProjectTable() {
|
|
19
|
+
const [query, setQuery] = useState("");
|
|
20
|
+
const [status, setStatus] = useState("all");
|
|
21
|
+
const [page, setPage] = useState(1);
|
|
22
|
+
const [selected, setSelected] = useState<readonly string[]>([]);
|
|
23
|
+
function resetResults() { setPage(1); setSelected([]); }
|
|
24
|
+
const visible = projects.filter(project =>
|
|
25
|
+
project.name.toLowerCase().includes(query.trim().toLowerCase()) &&
|
|
26
|
+
(status === "all" || project.status === status));
|
|
27
|
+
|
|
28
|
+
return <Stack gap="4">
|
|
29
|
+
<Inline gap="3" align="end">
|
|
30
|
+
<Field label="Search projects">{props => <SearchInput {...props}
|
|
31
|
+
value={query} onChange={event => {setQuery(event.currentTarget.value); resetResults();}} />}</Field>
|
|
32
|
+
<Field label="Status">{props => <Select {...props} value={status}
|
|
33
|
+
onChange={event => {setStatus(event.currentTarget.value); resetResults();}}>
|
|
34
|
+
<option value="all">All statuses</option>
|
|
35
|
+
<option value="Active">Active</option>
|
|
36
|
+
<option value="Draft">Draft</option>
|
|
37
|
+
</Select>}</Field>
|
|
38
|
+
{(query || status !== "all") && <Button variant="subtle"
|
|
39
|
+
onClick={() => {setQuery(""); setStatus("all"); resetResults();}}>Clear filters</Button>}
|
|
40
|
+
</Inline>
|
|
41
|
+
<DataTable caption="Projects" selectable pageSize={5}
|
|
42
|
+
page={page} onPageChange={setPage} selectedIds={selected} onSelectionChange={setSelected}
|
|
43
|
+
columns={[{id:"name",label:"Project",sortable:true},
|
|
44
|
+
{id:"status",label:"Status"}, {id:"members",label:"Members",sortable:true,align:"end"}]}
|
|
45
|
+
rows={visible.map(project => ({id:project.id,label:project.name,cells:{
|
|
46
|
+
name:project.name,status:project.status,members:project.members}}))} />
|
|
47
|
+
</Stack>;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Place inside FloodRoot and import the shared stylesheet once. Keep visible labels
|
|
52
|
+
for filters, including when defaults are active. A clear action resets actual
|
|
53
|
+
values. Expose active filters as removable Tag components when the filter set
|
|
54
|
+
gets larger; do not add a duplicate generic FilterBar component just for layout.
|
|
55
|
+
|
|
56
|
+
For remote data, debounce or submit at the host boundary, cancel obsolete requests
|
|
57
|
+
and map loading/error states explicitly. Do not pass an individual server page to
|
|
58
|
+
this client-paginated DataTable or interpret the page aggregate as server-wide
|
|
59
|
+
selection. Use Table + Pagination for a remote query contract.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Form submission
|
|
2
|
+
|
|
3
|
+
Keep validation, pending state and recovery explicit. Native validity runs
|
|
4
|
+
before submit. Application or server errors belong to the form and its fields.
|
|
5
|
+
|
|
6
|
+
```tsx
|
|
7
|
+
"use client";
|
|
8
|
+
import {useRef, useState} from "react";
|
|
9
|
+
import {Alert, Button, Field, Input, Stack} from "@flood-md/react";
|
|
10
|
+
|
|
11
|
+
export function ProjectForm({save}: {save: (data: FormData) => Promise<void>}) {
|
|
12
|
+
const locked = useRef(false);
|
|
13
|
+
const [pending, setPending] = useState(false);
|
|
14
|
+
const [error, setError] = useState("");
|
|
15
|
+
const [saved, setSaved] = useState(false);
|
|
16
|
+
return <form onSubmit={async event => {
|
|
17
|
+
event.preventDefault();
|
|
18
|
+
if (locked.current) return;
|
|
19
|
+
const data = new FormData(event.currentTarget);
|
|
20
|
+
locked.current = true;
|
|
21
|
+
setPending(true); setError(""); setSaved(false);
|
|
22
|
+
try { await save(data); setSaved(true); }
|
|
23
|
+
catch { setError("Could not save. Your changes are still here. Try again."); }
|
|
24
|
+
finally { locked.current = false; setPending(false); }
|
|
25
|
+
}} aria-busy={pending}>
|
|
26
|
+
<Stack gap="4">
|
|
27
|
+
<Field label="Project name">{props => <Input {...props} name="name" required readOnly={pending} />}</Field>
|
|
28
|
+
{error && <Alert tone="error" announcement="assertive">{error}</Alert>}
|
|
29
|
+
{saved && <Alert tone="success" announcement="polite">Project saved.</Alert>}
|
|
30
|
+
<Button type="submit" loading={pending}>Save project</Button>
|
|
31
|
+
</Stack>
|
|
32
|
+
</form>;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Capture FormData before disabling any native fields. This example preserves user
|
|
37
|
+
input after failure. Map returned field errors to Field and optionally ErrorSummary;
|
|
38
|
+
never pretend the request succeeded. The host supplies persistence, cancellation,
|
|
39
|
+
authentication and navigation. Place inside FloodRoot and import its CSS once.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Grouped form
|
|
2
|
+
|
|
3
|
+
Use a shared outer grid for peer groups, with the same surface padding and field
|
|
4
|
+
spacing. Each group owns its title and reading order. Two short fields stack
|
|
5
|
+
inside each group; the next row reuses the same tracks instead of inventing a
|
|
6
|
+
new four-column or uneven grid. This recipe illustrates workspace preferences,
|
|
7
|
+
not an invoice-specific screen or a universal two-column requirement.
|
|
8
|
+
|
|
9
|
+
Choose the number of tracks from the task and declared viewport. A long-address
|
|
10
|
+
group may span the row; a short field does not need its own column. Keep related
|
|
11
|
+
fields together in DOM order, including when an optional field disappears.
|
|
12
|
+
Use Grid, Fieldset, Surface and Field rather than recreating their recipes.
|
|
13
|
+
|
|
14
|
+
Import the shared stylesheet once and render inside FloodRoot. onApply receives
|
|
15
|
+
native FormData in the host; this recipe implements no persistence or permissions.
|
|
16
|
+
Those limits belong here in documentation, not as repeated captions in the form.
|
|
17
|
+
|
|
18
|
+
## Source
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
"use client";
|
|
22
|
+
import type {FormEvent} from 'react';
|
|
23
|
+
import {Button,Field,Fieldset,Grid,Input,Select,Stack,Surface} from '@flood-md/react';
|
|
24
|
+
|
|
25
|
+
/** Shared outer tracks; groups retain their own reading order and field ownership. */
|
|
26
|
+
export function GroupedForm({showBillingEmail=true,onApply}:{showBillingEmail?:boolean;onApply?:(values:FormData)=>void}) {
|
|
27
|
+
function submit(event:FormEvent<HTMLFormElement>){event.preventDefault();onApply?.(new FormData(event.currentTarget));}
|
|
28
|
+
return <form aria-label="Workspace settings" onSubmit={submit}>
|
|
29
|
+
<Stack gap="8">
|
|
30
|
+
<Grid columns={2} gap="6">
|
|
31
|
+
<Surface padding="6"><Fieldset legendSize="section" legend="Identity"><Stack gap="6">
|
|
32
|
+
<Field label="Workspace name" required>{props=><Input {...props} name="workspace" required />}</Field>
|
|
33
|
+
<Field label="Reference">{props=><Input {...props} name="reference" />}</Field>
|
|
34
|
+
</Stack></Fieldset></Surface>
|
|
35
|
+
<Surface padding="6"><Fieldset legendSize="section" legend="Locale"><Stack gap="6">
|
|
36
|
+
<Field label="Language">{props=><Select {...props} name="language" defaultValue="en"><option value="en">English</option><option value="ru">Русский</option></Select>}</Field>
|
|
37
|
+
<Field label="Time zone">{props=><Select {...props} name="timezone" defaultValue="UTC"><option value="UTC">UTC</option><option value="Asia/Almaty">Almaty</option></Select>}</Field>
|
|
38
|
+
</Stack></Fieldset></Surface>
|
|
39
|
+
<Surface padding="6"><Fieldset legendSize="section" legend="Primary contact"><Stack gap="6">
|
|
40
|
+
<Field label="Contact name">{props=><Input {...props} name="contact" />}</Field>
|
|
41
|
+
<Field label="Contact email">{props=><Input {...props} name="contactEmail" type="email" />}</Field>
|
|
42
|
+
</Stack></Fieldset></Surface>
|
|
43
|
+
<Surface padding="6"><Fieldset legendSize="section" legend="Billing contact"><Stack gap="6">
|
|
44
|
+
<Field label="Billing name">{props=><Input {...props} name="billing" />}</Field>
|
|
45
|
+
{showBillingEmail&&<Field label="Billing email">{props=><Input {...props} name="billingEmail" type="email" />}</Field>}
|
|
46
|
+
</Stack></Fieldset></Surface>
|
|
47
|
+
</Grid>
|
|
48
|
+
<Button type="submit">Apply settings</Button>
|
|
49
|
+
</Stack>
|
|
50
|
+
</form>;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Review
|
|
55
|
+
|
|
56
|
+
Compare left/right edges and gutters in both rows, label/control associations,
|
|
57
|
+
native required submission and omitted optional content. Inspect long labels and
|
|
58
|
+
enlarged text at the host's declared widths. Do not judge a form by zero page
|
|
59
|
+
overflow alone. Read the [forms workflow](/agent/references/flood-forms/SKILL.md)
|
|
60
|
+
and [content workflow](/agent/references/flood-interface-content/SKILL.md) before
|
|
61
|
+
adapting it. A useful form does not need a helper paragraph under every title.
|
|
62
|
+
|
|
63
|
+
Independent sections use Fieldset legendSize="section" and keep one shared outer
|
|
64
|
+
Grid across peer groups. Field labels retain the compact inner gap; Stack owns
|
|
65
|
+
row separation. The hierarchy workflow explains why section titles and choice
|
|
66
|
+
captions are different roles.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Select all
|
|
2
|
+
|
|
3
|
+
An aggregate checkbox derives its state from the selectable collection. Keep
|
|
4
|
+
unavailable rows outside that collection. This recipe adds no component export.
|
|
5
|
+
|
|
6
|
+
```tsx
|
|
7
|
+
"use client";
|
|
8
|
+
import {useState} from "react";
|
|
9
|
+
import {Checkbox, Stack} from "@flood-md/react";
|
|
10
|
+
|
|
11
|
+
export function Selection() {
|
|
12
|
+
const items = ["Design", "Engineering", "Support"];
|
|
13
|
+
const [selected, setSelected] = useState<string[]>([]);
|
|
14
|
+
const all = items.every(item => selected.includes(item));
|
|
15
|
+
const some = items.some(item => selected.includes(item));
|
|
16
|
+
return <Stack gap="2">
|
|
17
|
+
<Checkbox label="Select all" checked={all} indeterminate={some && !all}
|
|
18
|
+
onChange={event => setSelected(event.currentTarget.checked ? [...items] : [])} />
|
|
19
|
+
{items.map(item => <Checkbox key={item} label={item} checked={selected.includes(item)}
|
|
20
|
+
onChange={event => {
|
|
21
|
+
const checked = event.currentTarget.checked;
|
|
22
|
+
setSelected(previous => checked ? [...previous, item] : previous.filter(value => value !== item));
|
|
23
|
+
}} />)}
|
|
24
|
+
</Stack>;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Read `checked` before scheduling an update if the event may outlive the handler.
|
|
29
|
+
For remote collections, specify whether Select all means the visible page,
|
|
30
|
+
filtered results or every record. A client-side array does not imply server-wide
|
|
31
|
+
selection. Keep selection counts and bulk-action permissions in the host.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Split button
|
|
2
|
+
|
|
3
|
+
Keep the common action directly available and place alternatives in Menu.
|
|
4
|
+
ButtonGroup preserves independent native Tab stops; Menu owns popup navigation.
|
|
5
|
+
|
|
6
|
+
```tsx
|
|
7
|
+
import {Button, ButtonGroup, IconButton, Menu} from "@flood-md/react";
|
|
8
|
+
|
|
9
|
+
export function PublishActions({onAction}: {onAction: (action: string) => void}) {
|
|
10
|
+
return <ButtonGroup label="Publish actions">
|
|
11
|
+
<Button variant="subtle" onClick={() => onAction("publish")}>Publish</Button>
|
|
12
|
+
<Menu label="More publishing actions" align="end"
|
|
13
|
+
trigger={props => <IconButton {...props} label="More publishing actions" variant="subtle">
|
|
14
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
15
|
+
<path d="m6 9 6 6 6-6" />
|
|
16
|
+
</svg>
|
|
17
|
+
</IconButton>}
|
|
18
|
+
items={[{id:"schedule",label:"Schedule…"},{id:"draft",label:"Save draft"}]}
|
|
19
|
+
onAction={onAction} />
|
|
20
|
+
</ButtonGroup>;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The primary button performs an action; the icon button only opens alternatives.
|
|
25
|
+
Use matching variants and sizes. Do not make the whole group one button or nest
|
|
26
|
+
an action in another button. The host owns pending state and confirmation.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Table bulk actions
|
|
2
|
+
|
|
3
|
+
Compose DataTable, Toolbar, Button and AlertDialog with host-owned selection and
|
|
4
|
+
operation state. There is no separate BulkActions import. The runnable example
|
|
5
|
+
uses the same typed source as this page and only changes an in-memory collection.
|
|
6
|
+
|
|
7
|
+
## Choose the operation scope
|
|
8
|
+
|
|
9
|
+
DataTable receives the complete local collection. Its select-all checkbox selects
|
|
10
|
+
the current page; selected IDs on other pages are retained. The action uses all
|
|
11
|
+
selected eligible IDs in that collection. A protected row cannot be selected.
|
|
12
|
+
Remote selection, permissions, transport and server results remain host-owned;
|
|
13
|
+
this recipe does not imply selection of every remote search result.
|
|
14
|
+
|
|
15
|
+
Read workflow:composition, workflow:data-display and workflow:navigation for the
|
|
16
|
+
composition and toolbar. Apply feedback/accessibility/verification when checking
|
|
17
|
+
the operation. The knowledge catalog links the actual component contracts.
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
"use client";
|
|
21
|
+
import {useState} from 'react';
|
|
22
|
+
import {AlertDialog, Button, DataTable, Inline, Section, Stack, StatusIndicator, Surface, Text, Toolbar} from '@flood-md/react';
|
|
23
|
+
|
|
24
|
+
const initialProjects = [
|
|
25
|
+
{id:'system',name:'Design system'}, {id:'website',name:'Website'},
|
|
26
|
+
{id:'docs',name:'Documentation'}, {id:'research',name:'Research'},
|
|
27
|
+
{id:'preview',name:'Component preview'}, {id:'locked',name:'Protected project'},
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
/** Local host composition; no backend operation or new BulkActions export. */
|
|
31
|
+
export function TableBulkActions() {
|
|
32
|
+
const [projects,setProjects] = useState(initialProjects);
|
|
33
|
+
const [selected,setSelected] = useState<string[]>([]);
|
|
34
|
+
const [pending,setPending] = useState<string[] | null>(null);
|
|
35
|
+
const [message,setMessage] = useState('');
|
|
36
|
+
const [page,setPage] = useState(1);
|
|
37
|
+
const eligible = new Set(projects.filter(project=>project.id!=='locked').map(project=>project.id));
|
|
38
|
+
const selection = selected.filter(id=>eligible.has(id));
|
|
39
|
+
function archive() {
|
|
40
|
+
const ids = new Set(pending ?? []);
|
|
41
|
+
const count = projects.filter(project=>ids.has(project.id)&&eligible.has(project.id)).length;
|
|
42
|
+
setProjects(projects.filter(project=>!ids.has(project.id)||!eligible.has(project.id)));
|
|
43
|
+
setSelected([]);setPending(null);setPage(1);
|
|
44
|
+
setMessage(`${count} ${count===1?'project archived':'projects archived'}.`);
|
|
45
|
+
}
|
|
46
|
+
return <Surface padding="4">
|
|
47
|
+
<Section title="Projects">
|
|
48
|
+
<Stack gap="4">
|
|
49
|
+
<Inline gap="3">
|
|
50
|
+
<Text size="compact">{selection.length} selected</Text>
|
|
51
|
+
<Toolbar label="Bulk project actions">
|
|
52
|
+
<Inline gap="2">
|
|
53
|
+
<AlertDialog open={pending!==null} onOpenChange={open=>setPending(open?[...selection]:null)}
|
|
54
|
+
trigger={props=><Button {...props} size="sm" variant="subtle" disabled={!selection.length}>Archive projects</Button>}
|
|
55
|
+
title="Archive selected projects?" description={`${pending?.length??0} selected projects will leave this list.`}
|
|
56
|
+
confirmLabel="Archive selected" cancelLabel="Keep projects" confirmDisabled={!pending?.length} onConfirm={archive} />
|
|
57
|
+
<Button size="sm" variant="ghost" disabled={!selection.length} onClick={()=>setSelected([])}>Clear selection</Button>
|
|
58
|
+
</Inline>
|
|
59
|
+
</Toolbar>
|
|
60
|
+
</Inline>
|
|
61
|
+
<DataTable caption="Project list" hideCaption selectable pageSize={3} page={page} onPageChange={setPage} minWidth="28rem"
|
|
62
|
+
columns={[{id:'name',label:'Project',sortable:true},{id:'scope',label:'Scope'}]}
|
|
63
|
+
rows={projects.map(project=>({id:project.id,label:project.name,selectionDisabled:project.id==='locked',cells:{name:project.name,scope:project.id==='locked'?'Protected':'Standard'}}))}
|
|
64
|
+
selectedIds={selection} onSelectionChange={setSelected} />
|
|
65
|
+
<Inline gap="3">
|
|
66
|
+
<Button size="sm" variant="subtle" onClick={()=>{setProjects(initialProjects);setSelected([]);setPending(null);setPage(1);setMessage('Starting collection restored.');}}>Reset</Button>
|
|
67
|
+
{message && <StatusIndicator size="sm" label={message} tone="success" announce />}
|
|
68
|
+
</Inline>
|
|
69
|
+
</Stack>
|
|
70
|
+
</Section>
|
|
71
|
+
</Surface>;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Ownership and checks
|
|
76
|
+
|
|
77
|
+
Capture the proposed IDs when opening confirmation. Cancel must preserve rows
|
|
78
|
+
and selection. Confirm changes only the eligible IDs in that captured proposal.
|
|
79
|
+
The example then clears selection, reports the actual local count and allows
|
|
80
|
+
restoring the initial collection. A real asynchronous host needs separate pending,
|
|
81
|
+
failure and retry handling; do not report success before an accepted result.
|
|
82
|
+
|
|
83
|
+
Check no selection, select-all on one page, selection across pages, the protected
|
|
84
|
+
row, cancel and confirm, reset, keyboard focus restoration and narrow layout.
|
|
85
|
+
Use the table's ScrollArea rather than letting its minimum width overflow the
|
|
86
|
+
page. StatusIndicator owns the action result; do not replace it with custom
|
|
87
|
+
status markup. Scope and rendered quality require actual host checks, not just
|
|
88
|
+
a passing knowledge lookup.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Workspace review
|
|
2
|
+
|
|
3
|
+
[Try the local example](/playground/content#workspace-review). This composition
|
|
4
|
+
uses the same source for the live view and the example below. Import the Flood
|
|
5
|
+
stylesheet once and render it inside FloodRoot. No network, upload, authorization
|
|
6
|
+
or persistent save is implemented: acceptance captures native FormData in memory.
|
|
7
|
+
|
|
8
|
+
## Choose the owner
|
|
9
|
+
|
|
10
|
+
Section supplies the heading and supporting content. Field owns the Input/Select
|
|
11
|
+
associations; Checkbox owns its label and native form value. Button supplies submit
|
|
12
|
+
and reset actions. StatusIndicator describes draft/snapshot state without a
|
|
13
|
+
handmade dot. Alert announces local acceptance, and DescriptionList shows the
|
|
14
|
+
accepted values separately from the current draft.
|
|
15
|
+
|
|
16
|
+
The rendered form keeps task labels and operation state concise. Example-only
|
|
17
|
+
storage and permission limits are documented above; they are not repeated as
|
|
18
|
+
badges, helper paragraphs and drawer descriptions in the product composition.
|
|
19
|
+
|
|
20
|
+
Drawer owns modal focus, scroll locking and dismissal. Its FileList/FileItem rows
|
|
21
|
+
reuse FileMeta and StatusIndicator. The English example supplies an explicit
|
|
22
|
+
locale for file metadata, keeping server and browser formatting consistent.
|
|
23
|
+
No parallel popup, field or file chip is
|
|
24
|
+
implemented in this recipe. Stack, Inline and Surface own the composition's gaps
|
|
25
|
+
and containment. An unstyled section wrapper provides the demonstration anchor.
|
|
26
|
+
|
|
27
|
+
## Apply relevant skills
|
|
28
|
+
|
|
29
|
+
Read [composition](/agent/references/flood-composition/SKILL.md),
|
|
30
|
+
[forms](/agent/references/flood-forms/SKILL.md),
|
|
31
|
+
[spacing](/agent/references/flood-spacing/SKILL.md),
|
|
32
|
+
[overlays](/agent/references/flood-overlays/SKILL.md) and
|
|
33
|
+
[feedback](/agent/references/flood-feedback/SKILL.md) as those tasks arise.
|
|
34
|
+
The [skills index](/docs/skills) routes other work without loading every guide.
|
|
35
|
+
|
|
36
|
+
Controlled values are reset explicitly after checking that native reset was not
|
|
37
|
+
cancelled. Browser validity blocks an empty or whitespace-only name before
|
|
38
|
+
submission. Unchecked updates are absent from FormData. Changing a draft keeps
|
|
39
|
+
the accepted snapshot intact and marks it stale. Closing the drawer never resets
|
|
40
|
+
the form. The status uses text as well as color.
|
|
41
|
+
|
|
42
|
+
## Source
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
"use client";
|
|
46
|
+
import {useRef, useState, type FormEvent} from "react";
|
|
47
|
+
import {Button, Checkbox, DescriptionList, Drawer, Field, FileItem, FileList,
|
|
48
|
+
Inline, Input, Link, Section, Select, Stack, StatusIndicator, Surface, Text} from "@flood-md/react";
|
|
49
|
+
|
|
50
|
+
const defaults = {name: "Design workspace", visibility: "private", updates: true};
|
|
51
|
+
|
|
52
|
+
/** Host state and native form semantics; no persistence or upload transport. */
|
|
53
|
+
export function WorkspaceReview() {
|
|
54
|
+
const [draft, setDraft] = useState(defaults);
|
|
55
|
+
const [saved, setSaved] = useState<Record<string, string> | null>(null);
|
|
56
|
+
const [error, setError] = useState("");
|
|
57
|
+
const [filesOpen, setFilesOpen] = useState(false);
|
|
58
|
+
const nameRef = useRef<HTMLInputElement>(null);
|
|
59
|
+
|
|
60
|
+
function submit(event: FormEvent<HTMLFormElement>) {
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
const data = new FormData(event.currentTarget);
|
|
63
|
+
setSaved({name: String(data.get("workspace")), visibility: String(data.get("visibility")),
|
|
64
|
+
updates: data.has("updates") ? "On" : "Off"});
|
|
65
|
+
setError("");
|
|
66
|
+
}
|
|
67
|
+
function reset(event: FormEvent<HTMLFormElement>) {
|
|
68
|
+
const nativeEvent = event.nativeEvent;
|
|
69
|
+
queueMicrotask(() => {
|
|
70
|
+
if (nativeEvent.defaultPrevented) return;
|
|
71
|
+
setDraft(defaults); setSaved(null); setError("");
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const dirty = saved !== null && (saved.name !== draft.name || saved.visibility !== draft.visibility
|
|
75
|
+
|| saved.updates !== (draft.updates ? "On" : "Off"));
|
|
76
|
+
|
|
77
|
+
return <Surface padding="4">
|
|
78
|
+
<Section title="Workspace settings">
|
|
79
|
+
<Stack gap="6">
|
|
80
|
+
<form aria-label="Workspace review settings" onSubmit={submit} onReset={reset}>
|
|
81
|
+
<Stack gap="4">
|
|
82
|
+
<Field label="Workspace name" required error={error || undefined}>
|
|
83
|
+
{control => <Input {...control} ref={nameRef} name="workspace" required pattern={".*\\S.*"}
|
|
84
|
+
value={draft.name} onChange={event => {setDraft({...draft, name: event.currentTarget.value}); setError("");}}
|
|
85
|
+
onInvalid={() => setError("Enter a workspace name, including at least one non-space character.")} />}
|
|
86
|
+
</Field>
|
|
87
|
+
<Field label="Visibility">
|
|
88
|
+
{control => <Select {...control} name="visibility" value={draft.visibility}
|
|
89
|
+
onChange={event => setDraft({...draft, visibility: event.currentTarget.value})}>
|
|
90
|
+
<option value="private">Only me</option><option value="team">Project team</option>
|
|
91
|
+
</Select>}
|
|
92
|
+
</Field>
|
|
93
|
+
<Checkbox label="Product updates" name="updates" value="yes" checked={draft.updates}
|
|
94
|
+
onChange={event => setDraft({...draft, updates: event.currentTarget.checked})} />
|
|
95
|
+
<Inline gap="3">
|
|
96
|
+
<Button type="submit">Apply changes</Button><Button type="reset" variant="subtle">Reset settings</Button>
|
|
97
|
+
{saved && <StatusIndicator size="sm" tone={!dirty ? "success" : "neutral"}
|
|
98
|
+
label={dirty ? "Unapplied changes" : "Applied"} />}
|
|
99
|
+
</Inline>
|
|
100
|
+
</Stack>
|
|
101
|
+
</form>
|
|
102
|
+
{saved && <Stack gap="3">
|
|
103
|
+
<DescriptionList items={[
|
|
104
|
+
{id:"name", term:"Accepted name", description:saved.name},
|
|
105
|
+
{id:"visibility", term:"Accepted visibility", description:saved.visibility === "team" ? "Project team" : "Only me"},
|
|
106
|
+
{id:"updates", term:"Accepted updates", description:saved.updates},
|
|
107
|
+
]} />
|
|
108
|
+
</Stack>}
|
|
109
|
+
<Drawer title="Files"
|
|
110
|
+
open={filesOpen} onOpenChange={setFilesOpen} closeLabel="Close project files"
|
|
111
|
+
trigger={props => <Button {...props} variant="subtle">Review files</Button>}
|
|
112
|
+
footer={<Button onClick={() => setFilesOpen(false)}>Done reviewing</Button>}>
|
|
113
|
+
<Stack gap="4"><FileList label="Sample project files">
|
|
114
|
+
<FileItem lang="en" name="Research findings — international expansion and onboarding.pdf" format="PDF" size={2457600}
|
|
115
|
+
description={<StatusIndicator label="Ready for review" tone="info" size="sm" />} />
|
|
116
|
+
<FileItem lang="en" name="Brand guidelines.pdf" format="PDF" size={1048576}
|
|
117
|
+
description={<StatusIndicator label="Reviewed" tone="success" size="sm" />} />
|
|
118
|
+
</FileList></Stack>
|
|
119
|
+
</Drawer>
|
|
120
|
+
<Text as="p" size="helper" tone="subtle"><Link href="/docs/recipes/workspace-review">Read the composition and its checks</Link></Text>
|
|
121
|
+
</Stack>
|
|
122
|
+
</Section>
|
|
123
|
+
</Surface>;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Verify in the host
|
|
128
|
+
|
|
129
|
+
Exercise invalid submit and focus, corrected submit, unchecked values, dirty
|
|
130
|
+
drafts, normal/cancelled reset and the accepted snapshot. Open the drawer by
|
|
131
|
+
keyboard, dismiss it and verify focus returns to the trigger. Inspect its long
|
|
132
|
+
file names and metadata with enlarged text and RTL at a narrow width; local
|
|
133
|
+
scrolling must keep all content reachable without page overflow. These checks
|
|
134
|
+
support this recipe; they do not certify every possible host composition.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"role": "sys.color.accent.content",
|
|
3
|
+
"cssName": "--flood-sys-color-accent-content",
|
|
4
|
+
"description": "Accent text and metadata on neutral dark surfaces",
|
|
5
|
+
"contexts": [
|
|
6
|
+
{
|
|
7
|
+
"preset": "neutral",
|
|
8
|
+
"theme": "dark",
|
|
9
|
+
"id": "sys.color.accent.content",
|
|
10
|
+
"type": "color",
|
|
11
|
+
"cssName": "--flood-sys-color-accent-content",
|
|
12
|
+
"description": "Accent text and metadata on neutral dark surfaces",
|
|
13
|
+
"status": "experimental",
|
|
14
|
+
"visibility": "public",
|
|
15
|
+
"owner": "foundations",
|
|
16
|
+
"since": "0.2.4",
|
|
17
|
+
"usage": {
|
|
18
|
+
"allowed": [
|
|
19
|
+
"Accent text and metadata on neutral dark surfaces"
|
|
20
|
+
],
|
|
21
|
+
"avoid": [
|
|
22
|
+
"Keyboard focus indicators"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"value": {
|
|
26
|
+
"colorSpace": "srgb",
|
|
27
|
+
"components": [
|
|
28
|
+
1,
|
|
29
|
+
0.3607843137254902,
|
|
30
|
+
0.6588235294117647
|
|
31
|
+
],
|
|
32
|
+
"alpha": 1
|
|
33
|
+
},
|
|
34
|
+
"alias": "ref.color.accent.default",
|
|
35
|
+
"dependencies": [
|
|
36
|
+
"ref.color.accent.default"
|
|
37
|
+
],
|
|
38
|
+
"dependents": []
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|