@flood-md/agent 0.2.9 → 0.2.11
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 +33 -8
- package/README.md +35 -4
- package/SKILL.md +42 -0
- package/dist/catalog.json +8716 -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-app-shell.md +47 -0
- package/dist/materials/component-app-top-bar.md +36 -0
- package/dist/materials/component-aspect-ratio.md +36 -0
- package/dist/materials/component-autocomplete.md +54 -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-bulk-action-bar.md +52 -0
- package/dist/materials/component-button-group.md +39 -0
- package/dist/materials/component-button.md +44 -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 +41 -0
- package/dist/materials/component-collection-toolbar.md +68 -0
- package/dist/materials/component-collection-view-switcher.md +49 -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 +60 -0
- package/dist/materials/component-command-list.md +48 -0
- package/dist/materials/component-command-palette.md +53 -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 +43 -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 +70 -0
- package/dist/materials/component-date-field.md +57 -0
- package/dist/materials/component-date-picker.md +67 -0
- package/dist/materials/component-date-range-field.md +62 -0
- package/dist/materials/component-date-range-picker.md +73 -0
- package/dist/materials/component-date-time-picker.md +62 -0
- package/dist/materials/component-date-time-range-picker.md +70 -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 +51 -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-filter-condition.md +53 -0
- package/dist/materials/component-filter-group.md +55 -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 +43 -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-menubar.md +41 -0
- package/dist/materials/component-meter.md +43 -0
- package/dist/materials/component-metric.md +39 -0
- package/dist/materials/component-multi-select.md +62 -0
- package/dist/materials/component-navigation-group.md +51 -0
- package/dist/materials/component-navigation-item.md +59 -0
- package/dist/materials/component-navigation-list.md +38 -0
- package/dist/materials/component-navigation-tree.md +51 -0
- package/dist/materials/component-number-input.md +47 -0
- package/dist/materials/component-overflow-actions.md +47 -0
- package/dist/materials/component-page-header.md +40 -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 +48 -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 +53 -0
- package/dist/materials/component-select.md +45 -0
- package/dist/materials/component-sidebar.md +64 -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 +45 -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 +40 -0
- package/dist/materials/component-toolbar.md +46 -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 +95 -0
- package/dist/materials/guide-agents.md +103 -0
- package/dist/materials/guide-faq.md +84 -0
- package/dist/materials/guide-foundations.md +275 -0
- package/dist/materials/guide-installation.md +79 -0
- package/dist/materials/guide-interface-content.md +76 -0
- package/dist/materials/guide-introduction.md +42 -0
- package/dist/materials/guide-layout.md +222 -0
- package/dist/materials/guide-motion.md +69 -0
- package/dist/materials/guide-privacy.md +23 -0
- package/dist/materials/guide-project-ui.md +127 -0
- package/dist/materials/guide-skills.md +117 -0
- package/dist/materials/guide-theming.md +73 -0
- package/dist/materials/recipe-collection-views.md +648 -0
- package/dist/materials/recipe-command-palette.md +45 -0
- package/dist/materials/recipe-filter-bar.md +68 -0
- package/dist/materials/recipe-form-submission.md +39 -0
- package/dist/materials/recipe-grouped-form.md +71 -0
- package/dist/materials/recipe-navigation-workspace.md +222 -0
- package/dist/materials/recipe-record-management.md +296 -0
- package/dist/materials/recipe-record-workspace.md +207 -0
- package/dist/materials/recipe-select-all.md +31 -0
- package/dist/materials/recipe-settings-workspace.md +232 -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.context.base.action-disabled.json +41 -0
- package/dist/materials/token-sys.color.context.base.action-hover.json +41 -0
- package/dist/materials/token-sys.color.context.base.action-pressed.json +41 -0
- package/dist/materials/token-sys.color.context.base.action-rest.json +41 -0
- package/dist/materials/token-sys.color.context.base.avatar-background.json +41 -0
- package/dist/materials/token-sys.color.context.base.border-decorative.json +41 -0
- package/dist/materials/token-sys.color.context.base.divider-decorative.json +41 -0
- package/dist/materials/token-sys.color.context.base.field-background.json +41 -0
- package/dist/materials/token-sys.color.context.base.field-border.json +41 -0
- package/dist/materials/token-sys.color.context.base.field-disabled.json +41 -0
- package/dist/materials/token-sys.color.context.base.field-readonly.json +41 -0
- package/dist/materials/token-sys.color.context.base.indicator-track.json +41 -0
- package/dist/materials/token-sys.color.context.base.loading-placeholder.json +41 -0
- package/dist/materials/token-sys.color.context.base.muted-background.json +41 -0
- package/dist/materials/token-sys.color.context.base.on-surface-action-disabled.json +41 -0
- package/dist/materials/token-sys.color.context.base.on-surface-action-hover.json +41 -0
- package/dist/materials/token-sys.color.context.base.on-surface-action-pressed.json +41 -0
- package/dist/materials/token-sys.color.context.base.on-surface-action-rest.json +41 -0
- package/dist/materials/token-sys.color.context.base.selection-background.json +41 -0
- package/dist/materials/token-sys.color.context.base.supporting-background.json +41 -0
- package/dist/materials/token-sys.color.context.filled.action-disabled.json +41 -0
- package/dist/materials/token-sys.color.context.filled.action-hover.json +41 -0
- package/dist/materials/token-sys.color.context.filled.action-pressed.json +41 -0
- package/dist/materials/token-sys.color.context.filled.action-rest.json +41 -0
- package/dist/materials/token-sys.color.context.filled.avatar-background.json +41 -0
- package/dist/materials/token-sys.color.context.filled.border-decorative.json +41 -0
- package/dist/materials/token-sys.color.context.filled.divider-decorative.json +41 -0
- package/dist/materials/token-sys.color.context.filled.field-background.json +41 -0
- package/dist/materials/token-sys.color.context.filled.field-border.json +41 -0
- package/dist/materials/token-sys.color.context.filled.field-disabled.json +41 -0
- package/dist/materials/token-sys.color.context.filled.field-readonly.json +41 -0
- package/dist/materials/token-sys.color.context.filled.indicator-track.json +41 -0
- package/dist/materials/token-sys.color.context.filled.loading-placeholder.json +41 -0
- package/dist/materials/token-sys.color.context.filled.muted-background.json +41 -0
- package/dist/materials/token-sys.color.context.filled.selection-background.json +41 -0
- package/dist/materials/token-sys.color.context.filled.supporting-background.json +41 -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.field.readonly.json +41 -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.avatar.json +41 -0
- package/dist/materials/token-sys.color.surface.canvas.json +39 -0
- package/dist/materials/token-sys.color.surface.current.json +41 -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.muted.json +41 -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.color.surface.supporting.json +41 -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.distance-panel.json +36 -0
- package/dist/materials/token-sys.motion.distance-small.json +36 -0
- package/dist/materials/token-sys.motion.duration-enter.json +36 -0
- package/dist/materials/token-sys.motion.duration-exit.json +36 -0
- package/dist/materials/token-sys.motion.duration-fast.json +34 -0
- package/dist/materials/token-sys.motion.duration-layer.json +36 -0
- package/dist/materials/token-sys.motion.duration-loop.json +36 -0
- package/dist/materials/token-sys.motion.duration-normal.json +34 -0
- package/dist/materials/token-sys.motion.duration-press.json +36 -0
- package/dist/materials/token-sys.motion.duration-reduced.json +34 -0
- package/dist/materials/token-sys.motion.easing-enter.json +38 -0
- package/dist/materials/token-sys.motion.easing-exit.json +38 -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 +522 -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 +51 -1
- package/package.json +13 -1
- package/references/component-families.md +146 -0
- package/references/composition.md +4 -4
- package/references/customization.md +14 -0
- package/references/flood-composition/SKILL.md +34 -0
- package/references/flood-data-display/SKILL.md +149 -0
- package/references/flood-feedback/SKILL.md +49 -3
- package/references/flood-forms/SKILL.md +82 -2
- package/references/flood-foundations/SKILL.md +43 -0
- package/references/flood-hierarchy/SKILL.md +103 -0
- package/references/flood-interface-content/SKILL.md +163 -0
- package/references/flood-motion/SKILL.md +44 -0
- package/references/flood-navigation/SKILL.md +195 -0
- package/references/flood-overlays/SKILL.md +42 -0
- package/references/flood-records/SKILL.md +148 -0
- package/references/flood-spacing/SKILL.md +54 -0
- package/references/flood-verification/SKILL.md +72 -0
- package/references/interface-content-examples.md +51 -0
- package/references/knowledge.md +49 -0
- package/references/record-decisions.md +25 -0
- package/references/rendered-review.md +102 -0
- package/references/routing.md +1 -0
- package/references/spacing.md +30 -0
- package/rules.json +242 -6
- package/workflows.json +171 -10
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Settings workspace
|
|
2
|
+
|
|
3
|
+
[Open the working composition](/playground/settings).
|
|
4
|
+
|
|
5
|
+
Use a settings page when a person needs to review and change several related
|
|
6
|
+
preferences together. This example groups workspace details and notifications
|
|
7
|
+
in one form with a single save boundary. Fieldset names the groups, Field
|
|
8
|
+
associates labels and errors, and Grid lets related fields share tracks when
|
|
9
|
+
there is room. Use a standalone form control for a preference that should
|
|
10
|
+
apply immediately and has no shared save boundary.
|
|
11
|
+
|
|
12
|
+
## Save and discard
|
|
13
|
+
|
|
14
|
+
The host keeps a draft and the last accepted snapshot. Save validates the
|
|
15
|
+
workspace name, focuses its input if invalid and writes the full proposal
|
|
16
|
+
before announcing success. A write failure leaves the draft available for
|
|
17
|
+
retry. Discard restores the accepted snapshot and moves focus back to the first
|
|
18
|
+
field. Keep the save control available after success so a focused submit
|
|
19
|
+
button stays in the tab order.
|
|
20
|
+
|
|
21
|
+
This playground uses a dedicated browser storage key. The first visit starts
|
|
22
|
+
with defaults. If a saved snapshot cannot be read or parsed, show a retry
|
|
23
|
+
action and leave that snapshot intact. Use the host's actual persistence and
|
|
24
|
+
permission model when adapting the recipe.
|
|
25
|
+
|
|
26
|
+
## Source
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
"use client";
|
|
30
|
+
|
|
31
|
+
import { useEffect, useRef, useState, type FormEvent } from "react";
|
|
32
|
+
import {
|
|
33
|
+
Alert, Button, Container, Field, Fieldset, Grid, Heading, Inline,
|
|
34
|
+
Input, Select, Stack, Surface, Switch, Text,
|
|
35
|
+
} from "@flood-md/react";
|
|
36
|
+
import "./settings-workspace.css";
|
|
37
|
+
|
|
38
|
+
const storageKey = "flood:settings-workspace:v1";
|
|
39
|
+
const timeZones = ["UTC", "Europe/London", "America/New_York", "Asia/Tokyo"] as const;
|
|
40
|
+
const maxNameLength = 80;
|
|
41
|
+
type TimeZone = typeof timeZones[number];
|
|
42
|
+
|
|
43
|
+
interface WorkspaceSettings {
|
|
44
|
+
name: string;
|
|
45
|
+
timeZone: TimeZone;
|
|
46
|
+
assignmentAlerts: boolean;
|
|
47
|
+
weeklyDigest: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const defaults: WorkspaceSettings = {
|
|
51
|
+
name: "Studio North",
|
|
52
|
+
timeZone: "UTC",
|
|
53
|
+
assignmentAlerts: true,
|
|
54
|
+
weeklyDigest: false,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
function isTimeZone(value: unknown): value is TimeZone {
|
|
58
|
+
return timeZones.some(timeZone => timeZone === value);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function readSettings(): WorkspaceSettings {
|
|
62
|
+
const snapshot = window.localStorage.getItem(storageKey);
|
|
63
|
+
if (snapshot === null) return defaults;
|
|
64
|
+
const value: unknown = JSON.parse(snapshot);
|
|
65
|
+
if (
|
|
66
|
+
typeof value === "object" && value !== null &&
|
|
67
|
+
"name" in value && typeof value.name === "string" && value.name.trim() &&
|
|
68
|
+
value.name.length <= maxNameLength &&
|
|
69
|
+
"timeZone" in value && isTimeZone(value.timeZone) &&
|
|
70
|
+
"assignmentAlerts" in value && typeof value.assignmentAlerts === "boolean" &&
|
|
71
|
+
"weeklyDigest" in value && typeof value.weeklyDigest === "boolean"
|
|
72
|
+
) {
|
|
73
|
+
return {
|
|
74
|
+
name: value.name,
|
|
75
|
+
timeZone: value.timeZone,
|
|
76
|
+
assignmentAlerts: value.assignmentAlerts,
|
|
77
|
+
weeklyDigest: value.weeklyDigest,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
throw new Error("Invalid workspace settings");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function SettingsWorkspace() {
|
|
84
|
+
const [accepted, setAccepted] = useState<WorkspaceSettings | null>(null);
|
|
85
|
+
const [draft, setDraft] = useState(defaults);
|
|
86
|
+
const [readError, setReadError] = useState(false);
|
|
87
|
+
const [nameError, setNameError] = useState("");
|
|
88
|
+
const [saveError, setSaveError] = useState("");
|
|
89
|
+
const [notice, setNotice] = useState("");
|
|
90
|
+
const nameInput = useRef<HTMLInputElement>(null);
|
|
91
|
+
|
|
92
|
+
function load() {
|
|
93
|
+
try {
|
|
94
|
+
const settings = readSettings();
|
|
95
|
+
setAccepted(settings);
|
|
96
|
+
setDraft(settings);
|
|
97
|
+
setReadError(false);
|
|
98
|
+
} catch {
|
|
99
|
+
setReadError(true);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
useEffect(load, []);
|
|
104
|
+
|
|
105
|
+
const dirty = accepted !== null && (
|
|
106
|
+
draft.name !== accepted.name || draft.timeZone !== accepted.timeZone ||
|
|
107
|
+
draft.assignmentAlerts !== accepted.assignmentAlerts || draft.weeklyDigest !== accepted.weeklyDigest
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
function update<K extends keyof WorkspaceSettings>(key: K, value: WorkspaceSettings[K]) {
|
|
111
|
+
setDraft(current => ({ ...current, [key]: value }));
|
|
112
|
+
setNotice("");
|
|
113
|
+
if (key === "name") setNameError("");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function save(event: FormEvent<HTMLFormElement>) {
|
|
117
|
+
event.preventDefault();
|
|
118
|
+
if (!accepted) return;
|
|
119
|
+
const name = draft.name.trim();
|
|
120
|
+
if (!name) {
|
|
121
|
+
setNameError("Enter a workspace name.");
|
|
122
|
+
nameInput.current?.focus();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const proposal = { ...draft, name };
|
|
126
|
+
try {
|
|
127
|
+
window.localStorage.setItem(storageKey, JSON.stringify(proposal));
|
|
128
|
+
} catch {
|
|
129
|
+
setSaveError("Settings could not be saved. Try again.");
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
setAccepted(proposal);
|
|
133
|
+
setDraft(proposal);
|
|
134
|
+
setNameError("");
|
|
135
|
+
setSaveError("");
|
|
136
|
+
setNotice("Settings saved.");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function reset() {
|
|
140
|
+
if (!accepted) return;
|
|
141
|
+
setDraft(accepted);
|
|
142
|
+
setNameError("");
|
|
143
|
+
setSaveError("");
|
|
144
|
+
setNotice("Unsaved changes discarded.");
|
|
145
|
+
nameInput.current?.focus({ preventScroll: true });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<Container size="md" gutter="4">
|
|
150
|
+
<Stack gap="6">
|
|
151
|
+
<Heading level={1} size="page">Workspace settings</Heading>
|
|
152
|
+
{readError ? (
|
|
153
|
+
<Stack gap="4">
|
|
154
|
+
<Alert tone="error" announcement="polite">Settings could not be loaded.</Alert>
|
|
155
|
+
<Inline><Button variant="subtle" onClick={load}>Retry</Button></Inline>
|
|
156
|
+
</Stack>
|
|
157
|
+
) : accepted ? (
|
|
158
|
+
<Surface padding="6" elevation="raised">
|
|
159
|
+
<form aria-label="Workspace settings" onSubmit={save} noValidate>
|
|
160
|
+
<Stack gap="6">
|
|
161
|
+
<Fieldset legend="General" legendSize="section">
|
|
162
|
+
<Grid minItemWidth="14rem" gap="4">
|
|
163
|
+
<Field label="Workspace name" required error={nameError}>
|
|
164
|
+
{props => (
|
|
165
|
+
<Input {...props} ref={nameInput} name="name" maxLength={maxNameLength}
|
|
166
|
+
value={draft.name} onChange={event => update("name", event.currentTarget.value)} />
|
|
167
|
+
)}
|
|
168
|
+
</Field>
|
|
169
|
+
<Field label="Time zone">
|
|
170
|
+
{props => (
|
|
171
|
+
<Select {...props} name="timeZone" value={draft.timeZone}
|
|
172
|
+
onChange={event => {
|
|
173
|
+
const value = event.currentTarget.value;
|
|
174
|
+
if (isTimeZone(value)) update("timeZone", value);
|
|
175
|
+
}}>
|
|
176
|
+
{timeZones.map(timeZone => <option key={timeZone}>{timeZone}</option>)}
|
|
177
|
+
</Select>
|
|
178
|
+
)}
|
|
179
|
+
</Field>
|
|
180
|
+
</Grid>
|
|
181
|
+
</Fieldset>
|
|
182
|
+
<Fieldset legend="Notifications" legendSize="section">
|
|
183
|
+
<Stack gap="0" className="settings-switches">
|
|
184
|
+
<Switch className="settings-switch" label="New assignments" name="assignmentAlerts" checked={draft.assignmentAlerts}
|
|
185
|
+
onChange={event => update("assignmentAlerts", event.currentTarget.checked)} />
|
|
186
|
+
<Switch className="settings-switch" label="Weekly summary" name="weeklyDigest" checked={draft.weeklyDigest}
|
|
187
|
+
onChange={event => update("weeklyDigest", event.currentTarget.checked)} />
|
|
188
|
+
</Stack>
|
|
189
|
+
</Fieldset>
|
|
190
|
+
<Stack gap="4">
|
|
191
|
+
{saveError && <Alert tone="error" announcement="polite">{saveError}</Alert>}
|
|
192
|
+
<Inline gap="3">
|
|
193
|
+
<Button type="submit">Save settings</Button>
|
|
194
|
+
<Button variant="subtle" disabled={!dirty} onClick={reset}>Discard changes</Button>
|
|
195
|
+
<Text size="compact" tone="subtle" role="status">{notice}</Text>
|
|
196
|
+
</Inline>
|
|
197
|
+
</Stack>
|
|
198
|
+
</Stack>
|
|
199
|
+
</form>
|
|
200
|
+
</Surface>
|
|
201
|
+
) : <Text role="status">Loading settings…</Text>}
|
|
202
|
+
</Stack>
|
|
203
|
+
</Container>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
```css
|
|
209
|
+
.settings-switches {
|
|
210
|
+
max-inline-size: 16rem;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.flood-root .settings-switch {
|
|
214
|
+
inline-size: 100%;
|
|
215
|
+
justify-content: space-between;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.settings-switch input {
|
|
219
|
+
flex: none;
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Review
|
|
224
|
+
|
|
225
|
+
Check empty-name validation and its focus target, changes across sections,
|
|
226
|
+
discard, persistence after reload and read/write failure. Confirm the form
|
|
227
|
+
stacks at narrow widths and the labels remain readable with enlarged text.
|
|
228
|
+
|
|
229
|
+
Compare the legend with the first switch label, then compare the spacing
|
|
230
|
+
between the two switch labels. The row target already creates pitch. Align
|
|
231
|
+
the tracks at the end of a bounded column and verify that each label still
|
|
232
|
+
pairs clearly with its switch. See [visible weight](../layout.md#review-visible-weight).
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"role": "sys.color.action.danger.content",
|
|
3
|
+
"cssName": "--flood-sys-color-action-danger-content",
|
|
4
|
+
"description": "Destructive action text and icons",
|
|
5
|
+
"contexts": [
|
|
6
|
+
{
|
|
7
|
+
"preset": "neutral",
|
|
8
|
+
"theme": "dark",
|
|
9
|
+
"id": "sys.color.action.danger.content",
|
|
10
|
+
"type": "color",
|
|
11
|
+
"cssName": "--flood-sys-color-action-danger-content",
|
|
12
|
+
"description": "Destructive action text and icons",
|
|
13
|
+
"status": "experimental",
|
|
14
|
+
"visibility": "public",
|
|
15
|
+
"owner": "foundations",
|
|
16
|
+
"since": "0.2.4",
|
|
17
|
+
"usage": {
|
|
18
|
+
"allowed": [
|
|
19
|
+
"Destructive action text and icons"
|
|
20
|
+
],
|
|
21
|
+
"avoid": [
|
|
22
|
+
"Validation messages",
|
|
23
|
+
"Keyboard focus"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"value": {
|
|
27
|
+
"colorSpace": "srgb",
|
|
28
|
+
"components": [
|
|
29
|
+
1,
|
|
30
|
+
0.5411764705882353,
|
|
31
|
+
0.5411764705882353
|
|
32
|
+
],
|
|
33
|
+
"alpha": 1
|
|
34
|
+
},
|
|
35
|
+
"alias": "ref.color.feedback.error",
|
|
36
|
+
"dependencies": [
|
|
37
|
+
"ref.color.feedback.error"
|
|
38
|
+
],
|
|
39
|
+
"dependents": []
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"role": "sys.color.action.ghost.content",
|
|
3
|
+
"cssName": "--flood-sys-color-action-ghost-content",
|
|
4
|
+
"description": "ghost action content",
|
|
5
|
+
"contexts": [
|
|
6
|
+
{
|
|
7
|
+
"preset": "neutral",
|
|
8
|
+
"theme": "dark",
|
|
9
|
+
"id": "sys.color.action.ghost.content",
|
|
10
|
+
"type": "color",
|
|
11
|
+
"cssName": "--flood-sys-color-action-ghost-content",
|
|
12
|
+
"description": "ghost action content",
|
|
13
|
+
"status": "experimental",
|
|
14
|
+
"visibility": "public",
|
|
15
|
+
"owner": "foundations",
|
|
16
|
+
"since": "0.2.0",
|
|
17
|
+
"usage": {
|
|
18
|
+
"allowed": [
|
|
19
|
+
"ghost action content"
|
|
20
|
+
],
|
|
21
|
+
"avoid": [
|
|
22
|
+
"Standalone action without a visible containing context"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"value": {
|
|
26
|
+
"colorSpace": "srgb",
|
|
27
|
+
"components": [
|
|
28
|
+
1,
|
|
29
|
+
1,
|
|
30
|
+
1
|
|
31
|
+
],
|
|
32
|
+
"alpha": 1
|
|
33
|
+
},
|
|
34
|
+
"alias": "ref.color.neutral.0",
|
|
35
|
+
"dependencies": [
|
|
36
|
+
"ref.color.neutral.0"
|
|
37
|
+
],
|
|
38
|
+
"dependents": []
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"role": "sys.color.action.ghost.disabled-content",
|
|
3
|
+
"cssName": "--flood-sys-color-action-ghost-disabled-content",
|
|
4
|
+
"description": "ghost action disabled-content",
|
|
5
|
+
"contexts": [
|
|
6
|
+
{
|
|
7
|
+
"preset": "neutral",
|
|
8
|
+
"theme": "dark",
|
|
9
|
+
"id": "sys.color.action.ghost.disabled-content",
|
|
10
|
+
"type": "color",
|
|
11
|
+
"cssName": "--flood-sys-color-action-ghost-disabled-content",
|
|
12
|
+
"description": "ghost action disabled-content",
|
|
13
|
+
"status": "experimental",
|
|
14
|
+
"visibility": "public",
|
|
15
|
+
"owner": "foundations",
|
|
16
|
+
"since": "0.2.0",
|
|
17
|
+
"usage": {
|
|
18
|
+
"allowed": [
|
|
19
|
+
"ghost action disabled-content"
|
|
20
|
+
],
|
|
21
|
+
"avoid": [
|
|
22
|
+
"Standalone action without a visible containing context"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"value": {
|
|
26
|
+
"colorSpace": "srgb",
|
|
27
|
+
"components": [
|
|
28
|
+
0.47843137254901963,
|
|
29
|
+
0.47843137254901963,
|
|
30
|
+
0.47843137254901963
|
|
31
|
+
],
|
|
32
|
+
"alpha": 1
|
|
33
|
+
},
|
|
34
|
+
"alias": "ref.color.neutral.550",
|
|
35
|
+
"dependencies": [
|
|
36
|
+
"ref.color.neutral.550"
|
|
37
|
+
],
|
|
38
|
+
"dependents": []
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|