@grampro/kit 0.0.0-stage → 2.4.1
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/.gbs/skills/gbs-components/SKILL.md +190 -0
- package/.gbs/skills/gbs-components/references/accessibility.md +102 -0
- package/.gbs/skills/gbs-components/references/data-display.md +185 -0
- package/.gbs/skills/gbs-components/references/data-grid.md +116 -0
- package/.gbs/skills/gbs-components/references/forms.md +202 -0
- package/.gbs/skills/gbs-components/references/install.md +211 -0
- package/.gbs/skills/gbs-components/references/overlays.md +206 -0
- package/.gbs/skills/gbs-components/references/pickers.md +83 -0
- package/.gbs/skills/gbs-components/references/styling.md +246 -0
- package/.gbs/skills/gbs-components/references/toaster.md +57 -0
- package/CHANGELOG.md +173 -0
- package/LICENSE +15 -0
- package/README.md +193 -2
- package/index.cjs +1410 -0
- package/package.json +77 -6
- package/schema/passport-v1.schema.json +204 -0
- package/source/components/accordion/README.md +45 -0
- package/source/components/accordion/core/index.ts +2 -0
- package/source/components/accordion/core/open.ts +56 -0
- package/source/components/accordion/core/types.ts +17 -0
- package/source/components/accordion/index.ts +8 -0
- package/source/components/accordion/passport.json +259 -0
- package/source/components/accordion/react/Accordion.tsx +133 -0
- package/source/components/accordion/react/AccordionItem.tsx +120 -0
- package/source/components/accordion/react/context.ts +20 -0
- package/source/components/accordion/react/props.ts +13 -0
- package/source/components/accordion/styles.css +207 -0
- package/source/components/alert/README.md +39 -0
- package/source/components/alert/core/index.ts +2 -0
- package/source/components/alert/core/live.ts +25 -0
- package/source/components/alert/core/types.ts +7 -0
- package/source/components/alert/index.ts +5 -0
- package/source/components/alert/passport.json +250 -0
- package/source/components/alert/react/Alert.tsx +113 -0
- package/source/components/alert/react/icons.tsx +21 -0
- package/source/components/alert/react/locale.ts +5 -0
- package/source/components/alert/react/props.ts +11 -0
- package/source/components/alert/styles.css +154 -0
- package/source/components/avatar/core/identity.ts +103 -0
- package/source/components/avatar/core/index.ts +2 -0
- package/source/components/avatar/core/types.ts +12 -0
- package/source/components/avatar/index.ts +7 -0
- package/source/components/avatar/passport.json +294 -0
- package/source/components/avatar/react/Avatar.tsx +118 -0
- package/source/components/avatar/react/AvatarGroup.tsx +74 -0
- package/source/components/avatar/react/locale.ts +11 -0
- package/source/components/avatar/react/props.ts +6 -0
- package/source/components/avatar/styles.css +225 -0
- package/source/components/badge/README.md +37 -0
- package/source/components/badge/core/count.ts +37 -0
- package/source/components/badge/core/index.ts +2 -0
- package/source/components/badge/core/types.ts +11 -0
- package/source/components/badge/index.ts +7 -0
- package/source/components/badge/passport.json +332 -0
- package/source/components/badge/react/Badge.tsx +89 -0
- package/source/components/badge/react/Tag.tsx +82 -0
- package/source/components/badge/react/locale.ts +5 -0
- package/source/components/badge/react/props.ts +6 -0
- package/source/components/badge/styles.css +203 -0
- package/source/components/breadcrumb/README.md +34 -0
- package/source/components/breadcrumb/core/index.ts +4 -0
- package/source/components/breadcrumb/core/trail.ts +42 -0
- package/source/components/breadcrumb/core/types.ts +20 -0
- package/source/components/breadcrumb/index.ts +5 -0
- package/source/components/breadcrumb/passport.json +243 -0
- package/source/components/breadcrumb/react/Breadcrumb.tsx +177 -0
- package/source/components/breadcrumb/react/locale.ts +6 -0
- package/source/components/breadcrumb/react/props.ts +14 -0
- package/source/components/breadcrumb/styles.css +138 -0
- package/source/components/button/README.md +32 -0
- package/source/components/button/core/index.ts +3 -0
- package/source/components/button/core/state.ts +16 -0
- package/source/components/button/core/types.ts +28 -0
- package/source/components/button/index.ts +5 -0
- package/source/components/button/passport.json +402 -0
- package/source/components/button/passport.manual.json +31 -0
- package/source/components/button/react/Button.tsx +173 -0
- package/source/components/button/react/locale.ts +5 -0
- package/source/components/button/react/props.ts +23 -0
- package/source/components/button/styles.css +232 -0
- package/source/components/card/README.md +60 -0
- package/source/components/card/core/index.ts +4 -0
- package/source/components/card/core/trend.ts +32 -0
- package/source/components/card/core/types.ts +5 -0
- package/source/components/card/index.ts +5 -0
- package/source/components/card/passport.json +337 -0
- package/source/components/card/react/Card.tsx +133 -0
- package/source/components/card/react/Stat.tsx +127 -0
- package/source/components/card/react/props.ts +4 -0
- package/source/components/card/styles.css +230 -0
- package/source/components/checkbox/README.md +36 -0
- package/source/components/checkbox/core/group.ts +30 -0
- package/source/components/checkbox/core/index.ts +3 -0
- package/source/components/checkbox/core/types.ts +17 -0
- package/source/components/checkbox/index.ts +9 -0
- package/source/components/checkbox/passport.json +456 -0
- package/source/components/checkbox/react/Checkbox.tsx +147 -0
- package/source/components/checkbox/react/CheckboxGroup.tsx +149 -0
- package/source/components/checkbox/react/context.ts +16 -0
- package/source/components/checkbox/react/locale.ts +5 -0
- package/source/components/checkbox/react/props.ts +6 -0
- package/source/components/checkbox/styles.css +211 -0
- package/source/components/combobox/README.md +170 -0
- package/source/components/combobox/core/filter.ts +155 -0
- package/source/components/combobox/core/index.ts +16 -0
- package/source/components/combobox/core/types.ts +48 -0
- package/source/components/combobox/core/virtual.ts +67 -0
- package/source/components/combobox/index.ts +13 -0
- package/source/components/combobox/passport.json +456 -0
- package/source/components/combobox/react/Listbox.tsx +310 -0
- package/source/components/combobox/react/MultiSelect.tsx +265 -0
- package/source/components/combobox/react/Popover.tsx +38 -0
- package/source/components/combobox/react/Select.tsx +200 -0
- package/source/components/combobox/react/icons.tsx +11 -0
- package/source/components/combobox/react/locale.ts +16 -0
- package/source/components/combobox/react/props.ts +88 -0
- package/source/components/combobox/react/useCombobox.ts +409 -0
- package/source/components/combobox/styles.css +419 -0
- package/source/components/data-grid/README.md +233 -0
- package/source/components/data-grid/agent/coerce.ts +368 -0
- package/source/components/data-grid/agent/contract.ts +410 -0
- package/source/components/data-grid/agent/dataset.ts +92 -0
- package/source/components/data-grid/agent/engine.ts +470 -0
- package/source/components/data-grid/agent/executors.ts +155 -0
- package/source/components/data-grid/agent/index.ts +79 -0
- package/source/components/data-grid/agent/intent.ts +324 -0
- package/source/components/data-grid/agent/operations.ts +335 -0
- package/source/components/data-grid/agent/validate.ts +630 -0
- package/source/components/data-grid/agent/webmcp.ts +107 -0
- package/source/components/data-grid/core/columnHelper.ts +21 -0
- package/source/components/data-grid/core/columns.ts +288 -0
- package/source/components/data-grid/core/filtering.ts +237 -0
- package/source/components/data-grid/core/grid.ts +638 -0
- package/source/components/data-grid/core/index.ts +14 -0
- package/source/components/data-grid/core/rows.ts +64 -0
- package/source/components/data-grid/core/sorting.ts +133 -0
- package/source/components/data-grid/core/state.ts +82 -0
- package/source/components/data-grid/core/store.ts +52 -0
- package/source/components/data-grid/core/types.ts +302 -0
- package/source/components/data-grid/core/values.ts +98 -0
- package/source/components/data-grid/core/virtual.ts +85 -0
- package/source/components/data-grid/export/csv.ts +32 -0
- package/source/components/data-grid/export/download.ts +12 -0
- package/source/components/data-grid/export/pdf-font.ts +139 -0
- package/source/components/data-grid/export/pdf-writer.ts +113 -0
- package/source/components/data-grid/export/pdf.ts +379 -0
- package/source/components/data-grid/export/table.ts +73 -0
- package/source/components/data-grid/export/xlsx.ts +145 -0
- package/source/components/data-grid/export/zip.ts +87 -0
- package/source/components/data-grid/index.ts +14 -0
- package/source/components/data-grid/passport.json +1051 -0
- package/source/components/data-grid/passport.manual.json +255 -0
- package/source/components/data-grid/react/AskGrid.tsx +164 -0
- package/source/components/data-grid/react/Cell.tsx +282 -0
- package/source/components/data-grid/react/ColumnMenu.tsx +135 -0
- package/source/components/data-grid/react/DataGrid.tsx +335 -0
- package/source/components/data-grid/react/FilterForm.tsx +142 -0
- package/source/components/data-grid/react/HeaderRow.tsx +332 -0
- package/source/components/data-grid/react/Pagination.tsx +107 -0
- package/source/components/data-grid/react/Popover.tsx +35 -0
- package/source/components/data-grid/react/Row.tsx +85 -0
- package/source/components/data-grid/react/Toolbar.tsx +267 -0
- package/source/components/data-grid/react/Viewport.tsx +167 -0
- package/source/components/data-grid/react/context.ts +57 -0
- package/source/components/data-grid/react/hooks.ts +83 -0
- package/source/components/data-grid/react/icons.tsx +45 -0
- package/source/components/data-grid/react/keyboard.ts +110 -0
- package/source/components/data-grid/react/locale.ts +130 -0
- package/source/components/data-grid/styles.css +874 -0
- package/source/components/date-picker/README.md +141 -0
- package/source/components/date-picker/core/calendar.ts +266 -0
- package/source/components/date-picker/core/format.ts +170 -0
- package/source/components/date-picker/core/index.ts +41 -0
- package/source/components/date-picker/core/today.ts +72 -0
- package/source/components/date-picker/core/types.ts +68 -0
- package/source/components/date-picker/index.ts +16 -0
- package/source/components/date-picker/passport.json +407 -0
- package/source/components/date-picker/react/Calendar.tsx +160 -0
- package/source/components/date-picker/react/CalendarPanel.tsx +170 -0
- package/source/components/date-picker/react/DatePicker.tsx +249 -0
- package/source/components/date-picker/react/DateRangePicker.tsx +291 -0
- package/source/components/date-picker/react/MonthYearPanels.tsx +123 -0
- package/source/components/date-picker/react/Popover.tsx +45 -0
- package/source/components/date-picker/react/icons.tsx +15 -0
- package/source/components/date-picker/react/locale.ts +23 -0
- package/source/components/date-picker/react/props.ts +76 -0
- package/source/components/date-picker/react/useDatePicker.ts +557 -0
- package/source/components/date-picker/styles.css +445 -0
- package/source/components/dialog/README.md +39 -0
- package/source/components/dialog/core/api.ts +34 -0
- package/source/components/dialog/core/dialog.ts +11 -0
- package/source/components/dialog/core/index.ts +7 -0
- package/source/components/dialog/core/store.ts +81 -0
- package/source/components/dialog/core/types.ts +59 -0
- package/source/components/dialog/index.ts +7 -0
- package/source/components/dialog/passport.json +344 -0
- package/source/components/dialog/react/Dialog.tsx +279 -0
- package/source/components/dialog/react/DialogHost.tsx +45 -0
- package/source/components/dialog/react/icons.tsx +20 -0
- package/source/components/dialog/react/locale.ts +8 -0
- package/source/components/dialog/react/props.ts +13 -0
- package/source/components/dialog/styles.css +280 -0
- package/source/components/file-uploader/README.md +99 -0
- package/source/components/file-uploader/core/format.ts +79 -0
- package/source/components/file-uploader/core/index.ts +26 -0
- package/source/components/file-uploader/core/store.ts +432 -0
- package/source/components/file-uploader/core/transport.ts +154 -0
- package/source/components/file-uploader/core/types.ts +126 -0
- package/source/components/file-uploader/core/validate.ts +83 -0
- package/source/components/file-uploader/index.ts +7 -0
- package/source/components/file-uploader/passport.json +518 -0
- package/source/components/file-uploader/react/FileRow.tsx +268 -0
- package/source/components/file-uploader/react/FileUploader.tsx +511 -0
- package/source/components/file-uploader/react/icons.tsx +60 -0
- package/source/components/file-uploader/react/locale.ts +33 -0
- package/source/components/file-uploader/react/props.ts +31 -0
- package/source/components/file-uploader/react/useFileUploader.ts +32 -0
- package/source/components/file-uploader/styles.css +394 -0
- package/source/components/input/README.md +44 -0
- package/source/components/input/core/count.ts +5 -0
- package/source/components/input/core/index.ts +11 -0
- package/source/components/input/core/otp.ts +64 -0
- package/source/components/input/core/types.ts +14 -0
- package/source/components/input/index.ts +8 -0
- package/source/components/input/passport.json +536 -0
- package/source/components/input/react/Input.tsx +219 -0
- package/source/components/input/react/OtpInput.tsx +256 -0
- package/source/components/input/react/dom.ts +10 -0
- package/source/components/input/react/icons.tsx +17 -0
- package/source/components/input/react/locale.ts +9 -0
- package/source/components/input/react/props.ts +6 -0
- package/source/components/input/styles.css +295 -0
- package/source/components/menu/README.md +68 -0
- package/source/components/menu/core/index.ts +11 -0
- package/source/components/menu/core/navigation.ts +84 -0
- package/source/components/menu/core/types.ts +32 -0
- package/source/components/menu/index.ts +19 -0
- package/source/components/menu/passport.json +322 -0
- package/source/components/menu/react/Menu.tsx +371 -0
- package/source/components/menu/react/context.ts +31 -0
- package/source/components/menu/react/items.tsx +268 -0
- package/source/components/menu/react/locale.ts +6 -0
- package/source/components/menu/react/props.ts +4 -0
- package/source/components/menu/react/useMenuKeys.ts +124 -0
- package/source/components/menu/styles.css +224 -0
- package/source/components/modal/README.md +51 -0
- package/source/components/modal/core/dismiss.ts +29 -0
- package/source/components/modal/core/index.ts +3 -0
- package/source/components/modal/core/types.ts +27 -0
- package/source/components/modal/index.ts +5 -0
- package/source/components/modal/passport.json +289 -0
- package/source/components/modal/react/Modal.tsx +242 -0
- package/source/components/modal/react/icons.tsx +1 -0
- package/source/components/modal/react/locale.ts +5 -0
- package/source/components/modal/react/props.ts +17 -0
- package/source/components/modal/styles.css +241 -0
- package/source/components/number-input/README.md +53 -0
- package/source/components/number-input/core/format.ts +37 -0
- package/source/components/number-input/core/index.ts +4 -0
- package/source/components/number-input/core/parse.ts +118 -0
- package/source/components/number-input/core/step.ts +73 -0
- package/source/components/number-input/core/types.ts +32 -0
- package/source/components/number-input/index.ts +5 -0
- package/source/components/number-input/passport.json +541 -0
- package/source/components/number-input/react/NumberInput.tsx +465 -0
- package/source/components/number-input/react/icons.tsx +17 -0
- package/source/components/number-input/react/locale.ts +7 -0
- package/source/components/number-input/react/props.ts +11 -0
- package/source/components/number-input/styles.css +230 -0
- package/source/components/popover/README.md +44 -0
- package/source/components/popover/core/index.ts +2 -0
- package/source/components/popover/core/types.ts +12 -0
- package/source/components/popover/index.ts +4 -0
- package/source/components/popover/passport.json +238 -0
- package/source/components/popover/react/Popover.tsx +202 -0
- package/source/components/popover/react/locale.ts +5 -0
- package/source/components/popover/react/props.ts +4 -0
- package/source/components/popover/styles.css +148 -0
- package/source/components/progress/README.md +38 -0
- package/source/components/progress/core/index.ts +2 -0
- package/source/components/progress/core/progress.ts +40 -0
- package/source/components/progress/core/types.ts +23 -0
- package/source/components/progress/index.ts +7 -0
- package/source/components/progress/passport.json +270 -0
- package/source/components/progress/react/CircularProgress.tsx +106 -0
- package/source/components/progress/react/Progress.tsx +113 -0
- package/source/components/progress/react/locale.ts +7 -0
- package/source/components/progress/react/props.ts +6 -0
- package/source/components/progress/styles.css +200 -0
- package/source/components/radio-group/README.md +58 -0
- package/source/components/radio-group/core/group.ts +36 -0
- package/source/components/radio-group/core/index.ts +2 -0
- package/source/components/radio-group/core/types.ts +20 -0
- package/source/components/radio-group/index.ts +9 -0
- package/source/components/radio-group/passport.json +477 -0
- package/source/components/radio-group/react/Radio.tsx +144 -0
- package/source/components/radio-group/react/RadioGroup.tsx +179 -0
- package/source/components/radio-group/react/context.ts +18 -0
- package/source/components/radio-group/react/locale.ts +5 -0
- package/source/components/radio-group/react/props.ts +12 -0
- package/source/components/radio-group/styles.css +269 -0
- package/source/components/shared/README.md +54 -0
- package/source/components/shared/core/agent/adapter.ts +65 -0
- package/source/components/shared/core/agent/history.ts +120 -0
- package/source/components/shared/core/agent/index.ts +46 -0
- package/source/components/shared/core/agent/numbers.ts +217 -0
- package/source/components/shared/core/agent/schema.ts +180 -0
- package/source/components/shared/core/agent/types.ts +169 -0
- package/source/components/shared/core/agent/webmcp.ts +328 -0
- package/source/components/shared/core/cx.ts +9 -0
- package/source/components/shared/core/field.ts +35 -0
- package/source/components/shared/core/position.ts +124 -0
- package/source/components/shared/core/text.ts +14 -0
- package/source/components/shared/index.ts +17 -0
- package/source/components/shared/react/GramproAIProvider.tsx +50 -0
- package/source/components/shared/react/Popover.tsx +189 -0
- package/source/components/shared/react/icons.tsx +74 -0
- package/source/components/shared/react/useAskAgent.ts +217 -0
- package/source/components/shared/react/useControllableState.ts +42 -0
- package/source/components/shared/styles.css +79 -0
- package/source/components/shared/version.json +4 -0
- package/source/components/shared/version.ts +6 -0
- package/source/components/skeleton/README.md +58 -0
- package/source/components/skeleton/core/index.ts +3 -0
- package/source/components/skeleton/core/lines.ts +25 -0
- package/source/components/skeleton/core/types.ts +5 -0
- package/source/components/skeleton/index.ts +5 -0
- package/source/components/skeleton/passport.json +251 -0
- package/source/components/skeleton/react/Empty.tsx +51 -0
- package/source/components/skeleton/react/Skeleton.tsx +92 -0
- package/source/components/skeleton/react/props.ts +4 -0
- package/source/components/skeleton/styles.css +185 -0
- package/source/components/spinner/README.md +29 -0
- package/source/components/spinner/core/index.ts +3 -0
- package/source/components/spinner/core/types.ts +28 -0
- package/source/components/spinner/core/visibility.ts +34 -0
- package/source/components/spinner/index.ts +6 -0
- package/source/components/spinner/passport.json +245 -0
- package/source/components/spinner/react/Spinner.tsx +96 -0
- package/source/components/spinner/react/locale.ts +5 -0
- package/source/components/spinner/react/props.ts +4 -0
- package/source/components/spinner/react/useDelayedLoading.ts +39 -0
- package/source/components/spinner/styles.css +173 -0
- package/source/components/switch/README.md +46 -0
- package/source/components/switch/core/index.ts +2 -0
- package/source/components/switch/core/toggle.ts +54 -0
- package/source/components/switch/core/types.ts +9 -0
- package/source/components/switch/index.ts +5 -0
- package/source/components/switch/passport.json +421 -0
- package/source/components/switch/react/Switch.tsx +219 -0
- package/source/components/switch/react/locale.ts +5 -0
- package/source/components/switch/react/props.ts +12 -0
- package/source/components/switch/styles.css +227 -0
- package/source/components/tabs/README.md +32 -0
- package/source/components/tabs/core/index.ts +3 -0
- package/source/components/tabs/core/navigation.ts +54 -0
- package/source/components/tabs/core/types.ts +16 -0
- package/source/components/tabs/index.ts +5 -0
- package/source/components/tabs/passport.json +315 -0
- package/source/components/tabs/react/Tabs.tsx +306 -0
- package/source/components/tabs/react/context.ts +21 -0
- package/source/components/tabs/styles.css +263 -0
- package/source/components/textarea/README.md +39 -0
- package/source/components/textarea/core/count.ts +5 -0
- package/source/components/textarea/core/index.ts +4 -0
- package/source/components/textarea/core/size.ts +23 -0
- package/source/components/textarea/core/types.ts +17 -0
- package/source/components/textarea/index.ts +5 -0
- package/source/components/textarea/passport.json +382 -0
- package/source/components/textarea/react/Textarea.tsx +208 -0
- package/source/components/textarea/react/locale.ts +5 -0
- package/source/components/textarea/react/props.ts +4 -0
- package/source/components/textarea/styles.css +158 -0
- package/source/components/toaster/README.md +128 -0
- package/source/components/toaster/core/api.ts +87 -0
- package/source/components/toaster/core/index.ts +14 -0
- package/source/components/toaster/core/store.ts +211 -0
- package/source/components/toaster/core/toast.ts +12 -0
- package/source/components/toaster/core/types.ts +78 -0
- package/source/components/toaster/index.ts +6 -0
- package/source/components/toaster/passport.json +221 -0
- package/source/components/toaster/react/ToastItem.tsx +164 -0
- package/source/components/toaster/react/Toaster.tsx +187 -0
- package/source/components/toaster/react/icons.tsx +23 -0
- package/source/components/toaster/react/locale.ts +6 -0
- package/source/components/toaster/react/props.ts +15 -0
- package/source/components/toaster/react/useToasts.ts +11 -0
- package/source/components/toaster/styles.css +282 -0
- package/source/components/tooltip/README.md +43 -0
- package/source/components/tooltip/core/index.ts +4 -0
- package/source/components/tooltip/core/types.ts +4 -0
- package/source/components/tooltip/core/visibility.ts +34 -0
- package/source/components/tooltip/index.ts +3 -0
- package/source/components/tooltip/passport.json +170 -0
- package/source/components/tooltip/react/Tooltip.tsx +196 -0
- package/source/components/tooltip/react/props.ts +4 -0
- package/source/components/tooltip/styles.css +71 -0
- package/source/fallback/index.tsx +11 -0
- package/source/globalStyle.ts +74 -0
- package/source/hooks/SelectionHooks/type.ts +4 -0
- package/source/hooks/SelectionHooks/useClickOutside.ts +22 -0
- package/source/hooks/SelectionHooks/useMultiSelectState.ts +64 -0
- package/source/hooks/SelectionHooks/useSelectData.ts +58 -0
- package/source/hooks/SelectionHooks/useSelectState.ts +36 -0
- package/source/icon/Icon.tsx +102 -0
- package/source/icon/iconPaths.ts +206 -0
- package/source/legacy-components/bargraph/index.tsx +95 -0
- package/source/legacy-components/bargraph/type.ts +12 -0
- package/source/legacy-components/breadcrumb/index.tsx +66 -0
- package/source/legacy-components/breadcrumb/types.ts +10 -0
- package/source/legacy-components/button/index.tsx +42 -0
- package/source/legacy-components/card/index.tsx +31 -0
- package/source/legacy-components/checkbox/index.tsx +25 -0
- package/source/legacy-components/contextmenu/ContextMenu.tsx +87 -0
- package/source/legacy-components/contextmenu/ContextMenuItem.tsx +30 -0
- package/source/legacy-components/contextmenu/index.ts +2 -0
- package/source/legacy-components/contextmenu/types.ts +19 -0
- package/source/legacy-components/darkmode/index.tsx +55 -0
- package/source/legacy-components/datagrid/context/GridContext.tsx +215 -0
- package/source/legacy-components/datagrid/createTemplate.tsx +82 -0
- package/source/legacy-components/datagrid/hooks/index.ts +6 -0
- package/source/legacy-components/datagrid/hooks/useColumns.ts +33 -0
- package/source/legacy-components/datagrid/hooks/useDataSource.ts +54 -0
- package/source/legacy-components/datagrid/hooks/useFiltering.ts +169 -0
- package/source/legacy-components/datagrid/hooks/usePagination.ts +112 -0
- package/source/legacy-components/datagrid/hooks/useRowSelection.ts +48 -0
- package/source/legacy-components/datagrid/hooks/useSearch.ts +90 -0
- package/source/legacy-components/datagrid/index.tsx +28 -0
- package/source/legacy-components/datagrid/layout/FilterPopup.tsx +92 -0
- package/source/legacy-components/datagrid/layout/GridBody.tsx +184 -0
- package/source/legacy-components/datagrid/layout/GridPagination.tsx +119 -0
- package/source/legacy-components/datagrid/layout/GridToolbar.tsx +109 -0
- package/source/legacy-components/datagrid/layout/index.tsx +68 -0
- package/source/legacy-components/datagrid/type.ts +198 -0
- package/source/legacy-components/datepicker/index.tsx +365 -0
- package/source/legacy-components/datepicker/types.ts +12 -0
- package/source/legacy-components/dialog/index.tsx +44 -0
- package/source/legacy-components/dialog/types.ts +12 -0
- package/source/legacy-components/formrenderer/componentHandles/CheckBoxHandles.tsx +80 -0
- package/source/legacy-components/formrenderer/componentHandles/DatePickerHandles.tsx +93 -0
- package/source/legacy-components/formrenderer/componentHandles/InputHandles.tsx +106 -0
- package/source/legacy-components/formrenderer/componentHandles/MultiHandles.tsx +93 -0
- package/source/legacy-components/formrenderer/componentHandles/SelectHandles.tsx +95 -0
- package/source/legacy-components/formrenderer/helperFunctions.ts +72 -0
- package/source/legacy-components/formrenderer/index.tsx +93 -0
- package/source/legacy-components/formrenderer/types.ts +127 -0
- package/source/legacy-components/input/index.tsx +142 -0
- package/source/legacy-components/input/types.ts +10 -0
- package/source/legacy-components/materialInput/index.tsx +138 -0
- package/source/legacy-components/materialInput/types.ts +16 -0
- package/source/legacy-components/modal/index.tsx +152 -0
- package/source/legacy-components/modal/types.ts +19 -0
- package/source/legacy-components/multiselect/PortalDropDown.tsx +44 -0
- package/source/legacy-components/multiselect/index.tsx +269 -0
- package/source/legacy-components/multiselect/types.ts +26 -0
- package/source/legacy-components/navbar/AuthSection.tsx +98 -0
- package/source/legacy-components/navbar/MobileToggle.tsx +31 -0
- package/source/legacy-components/navbar/NavItemComponent.tsx +119 -0
- package/source/legacy-components/navbar/SearchBar.tsx +55 -0
- package/source/legacy-components/navbar/helperFunctions.ts +27 -0
- package/source/legacy-components/navbar/index.tsx +156 -0
- package/source/legacy-components/navbar/types.ts +69 -0
- package/source/legacy-components/select/PortalDropDown.tsx +59 -0
- package/source/legacy-components/select/index.tsx +249 -0
- package/source/legacy-components/select/types.ts +29 -0
- package/source/legacy-components/sidebar/components/MenuItem.tsx +101 -0
- package/source/legacy-components/sidebar/components/MenuSection.tsx +34 -0
- package/source/legacy-components/sidebar/components/SidebarFooter.tsx +50 -0
- package/source/legacy-components/sidebar/components/SidebarLogo.tsx +24 -0
- package/source/legacy-components/sidebar/components/SidebarMenu.tsx +29 -0
- package/source/legacy-components/sidebar/components/UserProfile.tsx +31 -0
- package/source/legacy-components/sidebar/hooks/useSidebarState.ts +41 -0
- package/source/legacy-components/sidebar/index.tsx +77 -0
- package/source/legacy-components/sidebar/type.ts +42 -0
- package/source/legacy-components/spinner/Stroke.tsx +89 -0
- package/source/legacy-components/spinner/index.tsx +54 -0
- package/source/legacy-components/spinner/types.ts +9 -0
- package/source/legacy-components/tabs/index.tsx +71 -0
- package/source/legacy-components/tabs/types.ts +16 -0
- package/source/legacy-components/textarea/index.tsx +123 -0
- package/source/legacy-components/textarea/types.ts +15 -0
- package/source/legacy-components/toast/ToastComponent.tsx +101 -0
- package/source/legacy-components/toast/ToastIcon.tsx +61 -0
- package/source/legacy-components/toast/index.tsx +42 -0
- package/source/legacy-components/toast/toastStore.ts +42 -0
- package/source/legacy-components/toast/types.ts +18 -0
- package/source/legacy-components/toast/useToast.ts +12 -0
- package/source/legacy-components/uploader/ProgressAnimation.tsx +50 -0
- package/source/legacy-components/uploader/UploadedFilePreview.tsx +130 -0
- package/source/legacy-components/uploader/index.tsx +311 -0
- package/source/legacy-components/uploader/types.ts +30 -0
- package/source/legacy-components/uploader/uploaderIcon.tsx +72 -0
- package/source/legacy-components/uploader/uploaderService.ts +134 -0
- package/source/legacy-components/useUploader/useUploader.tsx +310 -0
- package/source/legacy-components/usepaginateddata/usePaginatedData.ts +174 -0
- package/source/theme.ts +40 -0
- package/source/utils.ts +10 -0
- package/tools/env.cjs +61 -0
- package/tools/passport/cli.cjs +79 -0
- package/tools/passport/extract.cjs +493 -0
- package/tools/passport/index.cjs +185 -0
- package/tools/passport/merge.cjs +131 -0
- package/tools/passport/policy.cjs +65 -0
- package/tools/passport/validate.cjs +277 -0
- package/tools/ts-require.cjs +79 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The vocabulary an agent-operable component shares with its callers.
|
|
3
|
+
*
|
|
4
|
+
* Four things are kept apart on purpose, because they change for different
|
|
5
|
+
* reasons and at different times:
|
|
6
|
+
*
|
|
7
|
+
* OperationDefinition what a component knows how to do (static, from the passport)
|
|
8
|
+
* RuntimeContract what this instance can do, right now (per instance, per render)
|
|
9
|
+
* Intent what the caller is asking for (untrusted input)
|
|
10
|
+
* OperationExecutor how this instance actually performs it (per application)
|
|
11
|
+
*
|
|
12
|
+
* The last one is the reason this file exists. An operation must not be
|
|
13
|
+
* welded to an imperative handle: a grid performs `filter` by calling
|
|
14
|
+
* `GridApi.setFilter`, while a controlled component would perform its
|
|
15
|
+
* equivalent by calling the host's `onChange`. Same operation, same schema,
|
|
16
|
+
* different executor. Nothing here mentions either.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------- JSON Schema
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The slice of JSON Schema this library emits and checks. Deliberately small:
|
|
23
|
+
* it is what a constrained decoder and a validator both need, and no more.
|
|
24
|
+
*/
|
|
25
|
+
export interface JsonSchema {
|
|
26
|
+
$schema?: string;
|
|
27
|
+
title?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
type?: JsonSchemaType | readonly JsonSchemaType[];
|
|
30
|
+
const?: unknown;
|
|
31
|
+
enum?: readonly unknown[];
|
|
32
|
+
properties?: Readonly<Record<string, JsonSchema>>;
|
|
33
|
+
required?: readonly string[];
|
|
34
|
+
additionalProperties?: boolean | JsonSchema;
|
|
35
|
+
items?: JsonSchema;
|
|
36
|
+
minItems?: number;
|
|
37
|
+
maxItems?: number;
|
|
38
|
+
minLength?: number;
|
|
39
|
+
maxLength?: number;
|
|
40
|
+
minimum?: number;
|
|
41
|
+
maximum?: number;
|
|
42
|
+
pattern?: string;
|
|
43
|
+
oneOf?: readonly JsonSchema[];
|
|
44
|
+
anyOf?: readonly JsonSchema[];
|
|
45
|
+
default?: unknown;
|
|
46
|
+
examples?: readonly unknown[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type JsonSchemaType =
|
|
50
|
+
| "object"
|
|
51
|
+
| "array"
|
|
52
|
+
| "string"
|
|
53
|
+
| "number"
|
|
54
|
+
| "integer"
|
|
55
|
+
| "boolean"
|
|
56
|
+
| "null";
|
|
57
|
+
|
|
58
|
+
// ----------------------------------------------------------------- operations
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* One thing a component can be asked to do. This is the static half of the
|
|
62
|
+
* contract and mirrors the component's `passport.json` `operations` block.
|
|
63
|
+
*/
|
|
64
|
+
export interface OperationDefinition {
|
|
65
|
+
readonly name: string;
|
|
66
|
+
readonly summary: string;
|
|
67
|
+
/** JSON Schema for the operation's input, minus the `action` discriminator. */
|
|
68
|
+
readonly input?: JsonSchema;
|
|
69
|
+
/** Plain-language consequences, for a confirmation prompt. */
|
|
70
|
+
readonly effects?: readonly string[];
|
|
71
|
+
/** Whether undoing it is a matter of restoring the previous state. */
|
|
72
|
+
readonly reversible: boolean;
|
|
73
|
+
/** Leaves the page: downloads, prints, writes to the clipboard. */
|
|
74
|
+
readonly requiresConfirmation?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* The imperative method that happens to back this operation, when one does.
|
|
77
|
+
* Metadata only — never required. An operation performed through host state
|
|
78
|
+
* has no API method, and that is a normal case, not a gap.
|
|
79
|
+
*/
|
|
80
|
+
readonly apiMethod?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface ExecutionContext<TContract = unknown> {
|
|
84
|
+
readonly contract: TContract;
|
|
85
|
+
/** Report what would happen and change nothing. */
|
|
86
|
+
readonly dryRun: boolean;
|
|
87
|
+
readonly signal?: AbortSignal;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* How one instance performs one operation.
|
|
92
|
+
*
|
|
93
|
+
* Implementations close over whatever they need — an imperative handle, a
|
|
94
|
+
* state setter, a transport — and the rest of the pipeline never learns which.
|
|
95
|
+
*/
|
|
96
|
+
export interface OperationExecutor<TInput, TContract = unknown, TResult = void> {
|
|
97
|
+
readonly operation: string;
|
|
98
|
+
/** Set only when `execute` really does call that method. */
|
|
99
|
+
readonly apiMethod?: string;
|
|
100
|
+
execute(input: TInput, context: ExecutionContext<TContract>): TResult | Promise<TResult>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* An executor in a heterogeneous registry. `never` as the input type is sound
|
|
105
|
+
* here: a function taking a specific input is assignable to one taking
|
|
106
|
+
* `never`, so concrete executors slot in without a cast. Callers cast at the
|
|
107
|
+
* point of dispatch, where the validator has already proved the shape.
|
|
108
|
+
*/
|
|
109
|
+
export type RegisteredExecutor<TContract = unknown> = OperationExecutor<never, TContract, unknown>;
|
|
110
|
+
|
|
111
|
+
export type ExecutorRegistry<TContract = unknown> = ReadonlyMap<string, RegisteredExecutor<TContract>>;
|
|
112
|
+
|
|
113
|
+
// ----------------------------------------------------------------- validation
|
|
114
|
+
|
|
115
|
+
export type ValidationLayer =
|
|
116
|
+
| "schema"
|
|
117
|
+
| "reference"
|
|
118
|
+
| "coercion"
|
|
119
|
+
| "policy"
|
|
120
|
+
| "plausibility";
|
|
121
|
+
|
|
122
|
+
export interface ValidationIssue {
|
|
123
|
+
layer: ValidationLayer;
|
|
124
|
+
/** Stable, machine-readable. Messages may be reworded; codes may not. */
|
|
125
|
+
code: string;
|
|
126
|
+
message: string;
|
|
127
|
+
/** JSON pointer-ish path into the intent, when the issue has a location. */
|
|
128
|
+
path?: string;
|
|
129
|
+
suggestion?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Something the caller should see and agree to before the command runs. */
|
|
133
|
+
export interface ConfirmRequest {
|
|
134
|
+
code: string;
|
|
135
|
+
message: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export type ValidationResult<TCommand> =
|
|
139
|
+
| {
|
|
140
|
+
ok: true;
|
|
141
|
+
command: TCommand;
|
|
142
|
+
/** Non-blocking: coercions applied, plausibility notes. */
|
|
143
|
+
warnings: ValidationIssue[];
|
|
144
|
+
confirm: ConfirmRequest | null;
|
|
145
|
+
}
|
|
146
|
+
| {
|
|
147
|
+
ok: false;
|
|
148
|
+
/** The issue that stopped it, flattened for display. */
|
|
149
|
+
reason: string;
|
|
150
|
+
code: string;
|
|
151
|
+
layer: ValidationLayer;
|
|
152
|
+
suggestion?: string;
|
|
153
|
+
issues: ValidationIssue[];
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export const ok = <T>(
|
|
157
|
+
command: T,
|
|
158
|
+
warnings: ValidationIssue[] = [],
|
|
159
|
+
confirm: ConfirmRequest | null = null,
|
|
160
|
+
): ValidationResult<T> => ({ ok: true, command, warnings, confirm });
|
|
161
|
+
|
|
162
|
+
export const fail = <T>(issue: ValidationIssue, issues: ValidationIssue[] = []): ValidationResult<T> => ({
|
|
163
|
+
ok: false,
|
|
164
|
+
reason: issue.message,
|
|
165
|
+
code: issue.code,
|
|
166
|
+
layer: issue.layer,
|
|
167
|
+
...(issue.suggestion ? { suggestion: issue.suggestion } : {}),
|
|
168
|
+
issues: issues.length > 0 ? issues : [issue],
|
|
169
|
+
});
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WebMCP projection: exposing an already-validated command boundary to
|
|
3
|
+
* whatever agent is driving the browser.
|
|
4
|
+
*
|
|
5
|
+
* This is an adapter and nothing else. It owns no schema, no semantics and no
|
|
6
|
+
* execution path. The chain stays:
|
|
7
|
+
*
|
|
8
|
+
* component source → passport → runtime contract → intent schema
|
|
9
|
+
* → [this file] → the component's validator → its executors → the component
|
|
10
|
+
*
|
|
11
|
+
* Nothing here knows about a grid. A component's agent satisfies
|
|
12
|
+
* `ProjectableAgent` structurally, and everything component-specific arrives
|
|
13
|
+
* through `describe` and `summarise`.
|
|
14
|
+
*
|
|
15
|
+
* Why one tool and not one per operation: the operation list is not the
|
|
16
|
+
* agent's interface — the generated intent schema is, because that is where
|
|
17
|
+
* the contract and the validation layers already meet. Twenty-one operations
|
|
18
|
+
* exposed separately would be twenty-one schemas to keep in step with a
|
|
19
|
+
* contract that already describes itself.
|
|
20
|
+
*
|
|
21
|
+
* Surface notes, each of which cost a wrong run to learn:
|
|
22
|
+
*
|
|
23
|
+
* - It is `document.modelContext`. `navigator.modelContext` was the early
|
|
24
|
+
* spelling and is deprecated since Chromium 150.
|
|
25
|
+
* - Chrome hands `inputSchema` to the agent as a JSON *string*, and returns
|
|
26
|
+
* a tool result as a JSON string. That is the browser's wire format, not
|
|
27
|
+
* something to pre-serialise here.
|
|
28
|
+
* - It needs `--enable-features=WebMCPTesting`, the
|
|
29
|
+
* `chrome://flags/#enable-webmcp-testing` flag, or an origin-trial token.
|
|
30
|
+
*
|
|
31
|
+
* The specification is a Draft Community Group Report and is not on the W3C
|
|
32
|
+
* standards track, so this module is deliberately small and replaceable.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import type { ConfirmRequest, JsonSchema, ValidationIssue, ValidationLayer } from "./types";
|
|
36
|
+
|
|
37
|
+
// ----------------------------------------------------------- browser surface
|
|
38
|
+
|
|
39
|
+
/** One command the validator accepted, in the form this projection reports. */
|
|
40
|
+
export interface ProjectedCommand {
|
|
41
|
+
readonly intent: unknown;
|
|
42
|
+
readonly explain: { readonly summary: string };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* What the validator answers. Mirrors the component-level execution result;
|
|
47
|
+
* a component may carry extra fields, which are ignored here.
|
|
48
|
+
*/
|
|
49
|
+
export type ProjectedOutcome =
|
|
50
|
+
| { status: "done"; commands: readonly ProjectedCommand[]; warnings: readonly ValidationIssue[] }
|
|
51
|
+
| {
|
|
52
|
+
status: "needs-confirmation";
|
|
53
|
+
commands: readonly ProjectedCommand[];
|
|
54
|
+
warnings: readonly ValidationIssue[];
|
|
55
|
+
confirm: ConfirmRequest;
|
|
56
|
+
}
|
|
57
|
+
| {
|
|
58
|
+
status: "rejected";
|
|
59
|
+
reason: string;
|
|
60
|
+
code: string;
|
|
61
|
+
layer: ValidationLayer;
|
|
62
|
+
suggestion?: string;
|
|
63
|
+
}
|
|
64
|
+
| { status: "clarify"; question: string; options?: readonly string[] }
|
|
65
|
+
| { status: "declined"; reason: string };
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The part of a component's agent this projection uses.
|
|
69
|
+
*
|
|
70
|
+
* Structural on purpose: a DataGrid agent, a DatePicker agent or a test double
|
|
71
|
+
* satisfies it without importing anything from here.
|
|
72
|
+
*/
|
|
73
|
+
export interface ProjectableAgent {
|
|
74
|
+
/** The generated per-instance schema for one intent. */
|
|
75
|
+
schema(): JsonSchema;
|
|
76
|
+
/** Validate without changing anything. */
|
|
77
|
+
validate(intent: unknown): ProjectedOutcome;
|
|
78
|
+
execute(intent: unknown, options?: { confirm?: boolean }): Promise<ProjectedOutcome>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** The slice of the WebMCP surface this projection touches. */
|
|
82
|
+
export interface ModelContext {
|
|
83
|
+
registerTool(descriptor: {
|
|
84
|
+
name: string;
|
|
85
|
+
description: string;
|
|
86
|
+
inputSchema: unknown;
|
|
87
|
+
execute(input: unknown): Promise<unknown>;
|
|
88
|
+
}): void | Promise<void>;
|
|
89
|
+
getTools?(): unknown;
|
|
90
|
+
executeTool?(tool: unknown, input: unknown): Promise<unknown>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
declare global {
|
|
94
|
+
interface Document {
|
|
95
|
+
modelContext?: ModelContext;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// -------------------------------------------------------------------- result
|
|
100
|
+
|
|
101
|
+
/** What the agent gets back, before the MCP content envelope is put round it. */
|
|
102
|
+
export interface ToolResultPayload extends Record<string, unknown> {
|
|
103
|
+
ok: boolean;
|
|
104
|
+
status: string;
|
|
105
|
+
message: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface ToolCallLog {
|
|
109
|
+
readonly input: unknown;
|
|
110
|
+
readonly result: ToolResultPayload;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface RegistrationResult {
|
|
114
|
+
registered: boolean;
|
|
115
|
+
toolName: string;
|
|
116
|
+
/** Why not, when `registered` is false. Safe to show a developer. */
|
|
117
|
+
reason?: string;
|
|
118
|
+
/** The schema handed to the agent, for inspection in a test or a UI. */
|
|
119
|
+
inputSchema?: JsonSchema;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface RegisterAgentToolOptions<TAgent extends ProjectableAgent> {
|
|
123
|
+
/** The tool name the agent sees. One per page. */
|
|
124
|
+
name: string;
|
|
125
|
+
/** Natural-language description, built from the live contract. */
|
|
126
|
+
describe: (agent: TAgent) => string;
|
|
127
|
+
/** Extra fields merged into a successful result — row counts, undo state. */
|
|
128
|
+
summarise?: (agent: TAgent) => Record<string, unknown>;
|
|
129
|
+
/** How many operations may be sent in one call. Default 8. */
|
|
130
|
+
maxIntents?: number;
|
|
131
|
+
/** Description for the `intents` array itself. */
|
|
132
|
+
intentsDescription?: string;
|
|
133
|
+
/** Observe every call, for a UI log or a test. Must not throw. */
|
|
134
|
+
onCall?: (entry: ToolCallLog) => void;
|
|
135
|
+
/**
|
|
136
|
+
* Where to register. Defaults to `document.modelContext`. Supplying one is
|
|
137
|
+
* for tests and for hosts that polyfill the surface elsewhere.
|
|
138
|
+
*/
|
|
139
|
+
modelContext?: ModelContext;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const UNAVAILABLE =
|
|
143
|
+
"document.modelContext is unavailable. Chrome needs --enable-features=WebMCPTesting, " +
|
|
144
|
+
"the chrome://flags/#enable-webmcp-testing flag, or an origin-trial token.";
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Whether this page can register WebMCP tools at all.
|
|
148
|
+
*
|
|
149
|
+
* Guards `document` rather than assuming it: this module is imported by code
|
|
150
|
+
* that also runs during server rendering, where touching `document` throws.
|
|
151
|
+
*/
|
|
152
|
+
export function webmcpAvailable(modelContext?: ModelContext): boolean {
|
|
153
|
+
const target = modelContext ?? (typeof document === "undefined" ? undefined : document.modelContext);
|
|
154
|
+
return typeof target?.registerTool === "function";
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The tool's input schema, derived from the live contract.
|
|
159
|
+
*
|
|
160
|
+
* Not hand-written. `agent.schema()` is the generated per-instance schema, so
|
|
161
|
+
* a tool registered against a component with different columns, operators or
|
|
162
|
+
* policy advertises different arguments automatically.
|
|
163
|
+
*/
|
|
164
|
+
export function buildToolInputSchema(
|
|
165
|
+
agent: ProjectableAgent,
|
|
166
|
+
options: { maxIntents?: number; intentsDescription?: string } = {},
|
|
167
|
+
): JsonSchema {
|
|
168
|
+
return {
|
|
169
|
+
type: "object",
|
|
170
|
+
additionalProperties: false,
|
|
171
|
+
required: ["intents"],
|
|
172
|
+
properties: {
|
|
173
|
+
intents: {
|
|
174
|
+
type: "array",
|
|
175
|
+
minItems: 1,
|
|
176
|
+
maxItems: options.maxIntents ?? 8,
|
|
177
|
+
description:
|
|
178
|
+
options.intentsDescription ??
|
|
179
|
+
"Operations to apply in order. Several filters on different fields combine with AND.",
|
|
180
|
+
items: agent.schema(),
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Registers one tool, if the browser has WebMCP.
|
|
188
|
+
*
|
|
189
|
+
* `execute` runs the production pipeline and nothing else:
|
|
190
|
+
*
|
|
191
|
+
* validate → a refusal is returned as the validator wrote it
|
|
192
|
+
* confirm → anything irreversible stops here and asks, rather than running
|
|
193
|
+
* execute → only after validation passed
|
|
194
|
+
*
|
|
195
|
+
* There is no repair, no retry, and no path that exists only for WebMCP. An
|
|
196
|
+
* agent sending something the component cannot do gets the same refusal, with
|
|
197
|
+
* the same code and layer, that a form would have got.
|
|
198
|
+
*/
|
|
199
|
+
export function registerAgentTool<TAgent extends ProjectableAgent>(
|
|
200
|
+
agent: TAgent,
|
|
201
|
+
options: RegisterAgentToolOptions<TAgent>,
|
|
202
|
+
): RegistrationResult {
|
|
203
|
+
const modelContext =
|
|
204
|
+
options.modelContext ?? (typeof document === "undefined" ? undefined : document.modelContext);
|
|
205
|
+
|
|
206
|
+
if (typeof modelContext?.registerTool !== "function") {
|
|
207
|
+
return { registered: false, toolName: options.name, reason: UNAVAILABLE };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const inputSchema = buildToolInputSchema(agent, options);
|
|
211
|
+
|
|
212
|
+
modelContext.registerTool({
|
|
213
|
+
name: options.name,
|
|
214
|
+
description: options.describe(agent),
|
|
215
|
+
inputSchema,
|
|
216
|
+
|
|
217
|
+
async execute(rawInput: unknown) {
|
|
218
|
+
const intents = (rawInput as { intents?: unknown } | null | undefined)?.intents;
|
|
219
|
+
|
|
220
|
+
const reply = (payload: ToolResultPayload) => {
|
|
221
|
+
try {
|
|
222
|
+
options.onCall?.({ input: rawInput, result: payload });
|
|
223
|
+
} catch {
|
|
224
|
+
/* A broken observer must not turn a good command into an error. */
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
// MCP's content shape, so an agent reading text gets something useful…
|
|
228
|
+
content: [{ type: "text", text: payload.message }],
|
|
229
|
+
// …and the structured result for anything that wants to inspect it.
|
|
230
|
+
structuredContent: payload,
|
|
231
|
+
isError: payload.ok === false,
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
if (!Array.isArray(intents) || intents.length === 0) {
|
|
236
|
+
return reply({
|
|
237
|
+
ok: false,
|
|
238
|
+
status: "rejected",
|
|
239
|
+
code: "missing-intents",
|
|
240
|
+
message: '"intents" must be a non-empty array of operations.',
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Layer one of the real pipeline. Nothing has touched the component yet. */
|
|
245
|
+
let checked: ProjectedOutcome;
|
|
246
|
+
try {
|
|
247
|
+
checked = agent.validate(intents);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
return reply({
|
|
250
|
+
ok: false,
|
|
251
|
+
status: "rejected",
|
|
252
|
+
code: "validator-threw",
|
|
253
|
+
message: error instanceof Error ? error.message : String(error),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (checked.status === "rejected") {
|
|
258
|
+
return reply({
|
|
259
|
+
ok: false,
|
|
260
|
+
status: "rejected",
|
|
261
|
+
code: checked.code,
|
|
262
|
+
layer: checked.layer,
|
|
263
|
+
suggestion: checked.suggestion,
|
|
264
|
+
message: checked.reason,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (checked.status === "clarify") {
|
|
269
|
+
return reply({
|
|
270
|
+
ok: false,
|
|
271
|
+
status: "clarify",
|
|
272
|
+
message: checked.question,
|
|
273
|
+
options: checked.options,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (checked.status === "declined") {
|
|
278
|
+
return reply({ ok: false, status: "declined", message: checked.reason });
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (checked.status === "needs-confirmation") {
|
|
282
|
+
/*
|
|
283
|
+
* An agent does not get to skip a confirmation a person would see. The
|
|
284
|
+
* component is left untouched and the request is handed back.
|
|
285
|
+
*/
|
|
286
|
+
return reply({
|
|
287
|
+
ok: false,
|
|
288
|
+
status: "needs-confirmation",
|
|
289
|
+
code: checked.confirm.code,
|
|
290
|
+
message: checked.confirm.message,
|
|
291
|
+
explain: checked.commands.map((command) => command.explain.summary),
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let run: ProjectedOutcome;
|
|
296
|
+
try {
|
|
297
|
+
run = await agent.execute(intents);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
return reply({
|
|
300
|
+
ok: false,
|
|
301
|
+
status: "failed",
|
|
302
|
+
code: "executor-threw",
|
|
303
|
+
message: error instanceof Error ? error.message : String(error),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (run.status !== "done") {
|
|
308
|
+
return reply({
|
|
309
|
+
ok: false,
|
|
310
|
+
status: run.status,
|
|
311
|
+
message:
|
|
312
|
+
"reason" in run ? run.reason : "question" in run ? run.question : run.status,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return reply({
|
|
317
|
+
ok: true,
|
|
318
|
+
status: "done",
|
|
319
|
+
message: run.commands.map((command) => command.explain.summary).join("; "),
|
|
320
|
+
applied: run.commands.map((command) => command.intent),
|
|
321
|
+
warnings: run.warnings.map((warning) => `${warning.code}: ${warning.message}`),
|
|
322
|
+
...(options.summarise?.(agent) ?? {}),
|
|
323
|
+
});
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
return { registered: true, toolName: options.name, inputSchema };
|
|
328
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Joins class names, dropping anything falsy.
|
|
3
|
+
*
|
|
4
|
+
* Every component builds its class strings with this, so a `className` or
|
|
5
|
+
* `classNames` prop that is `undefined` contributes nothing rather than the
|
|
6
|
+
* string "undefined".
|
|
7
|
+
*/
|
|
8
|
+
export const cx = (...names: (string | false | null | undefined)[]) =>
|
|
9
|
+
names.filter(Boolean).join(" ");
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { cx } from "./cx";
|
|
2
|
+
|
|
3
|
+
export interface DescribedByParts {
|
|
4
|
+
/** An `aria-describedby` the caller passed in; kept first so it reads first. */
|
|
5
|
+
extra?: string;
|
|
6
|
+
/** Renders `#{id}-hint`. */
|
|
7
|
+
hint?: unknown;
|
|
8
|
+
/** Renders `#{id}-description`. */
|
|
9
|
+
description?: unknown;
|
|
10
|
+
/** Renders `#{id}-error`. */
|
|
11
|
+
error?: unknown;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The `aria-describedby` for a form control, built from whichever of its hint,
|
|
16
|
+
* description and error are actually rendered.
|
|
17
|
+
*
|
|
18
|
+
* Every control derives the ids the same way (`{id}-description`, `{id}-error`),
|
|
19
|
+
* so the helper owns both the ids and their order: a screen reader reads the
|
|
20
|
+
* caller's own description first, then the hint, then ours, and the error last,
|
|
21
|
+
* which is the part that changes and that the listener is waiting for.
|
|
22
|
+
*
|
|
23
|
+
* Returns `undefined` rather than `""` when nothing is described, because an
|
|
24
|
+
* empty `aria-describedby` still points at nothing and confuses some readers.
|
|
25
|
+
*/
|
|
26
|
+
export function describeField(id: string, parts: DescribedByParts): string | undefined {
|
|
27
|
+
return (
|
|
28
|
+
cx(
|
|
29
|
+
typeof parts.extra === "string" ? parts.extra : "",
|
|
30
|
+
parts.hint ? `${id}-hint` : "",
|
|
31
|
+
parts.description ? `${id}-description` : "",
|
|
32
|
+
parts.error ? `${id}-error` : "",
|
|
33
|
+
) || undefined
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/** The side of the anchor a popover is placed on. */
|
|
2
|
+
export type Side = "top" | "bottom" | "left" | "right";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Which edge of the anchor the popover lines up with, in reading order, or
|
|
6
|
+
* `center` to share its midpoint.
|
|
7
|
+
*/
|
|
8
|
+
export type Align = "start" | "center" | "end";
|
|
9
|
+
|
|
10
|
+
export interface Size {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AnchorRect extends Size {
|
|
16
|
+
top: number;
|
|
17
|
+
right: number;
|
|
18
|
+
bottom: number;
|
|
19
|
+
left: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface PlacementOptions {
|
|
23
|
+
/** The side to try first. */
|
|
24
|
+
side: Side;
|
|
25
|
+
align: Align;
|
|
26
|
+
/** Distance between the anchor and the popover. */
|
|
27
|
+
gap: number;
|
|
28
|
+
/** Space kept between the popover and the edge of the viewport. */
|
|
29
|
+
edge: number;
|
|
30
|
+
/** Mirrors `left`/`right` and swaps which edge `align` means. */
|
|
31
|
+
rtl: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The content scrolls, so the popover may be capped to the space available
|
|
34
|
+
* and should prefer whichever side has more of it. Fixed-size panels leave
|
|
35
|
+
* this off and only move when they fully fit on the other side.
|
|
36
|
+
*/
|
|
37
|
+
fitHeight: boolean;
|
|
38
|
+
/** Floor for the cap, so a cramped viewport still shows something. */
|
|
39
|
+
minHeight: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface Placement {
|
|
43
|
+
left: number;
|
|
44
|
+
top: number;
|
|
45
|
+
/** Where it actually ended up, which is not the requested side after a flip. */
|
|
46
|
+
side: Side;
|
|
47
|
+
/** Only when `fitHeight` asked for one. */
|
|
48
|
+
maxHeight?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const clamp = (value: number, min: number, max: number) =>
|
|
52
|
+
Math.min(Math.max(value, min), Math.max(min, max));
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Where to put a popover: on the requested side of its anchor, moved to the
|
|
56
|
+
* opposite side when there is no room, and kept inside the viewport.
|
|
57
|
+
*
|
|
58
|
+
* Pure arithmetic, so the rules can be tested without a browser. The caller
|
|
59
|
+
* measures, this decides, the caller writes the styles.
|
|
60
|
+
*/
|
|
61
|
+
export function placePopover(
|
|
62
|
+
anchor: AnchorRect,
|
|
63
|
+
size: Size,
|
|
64
|
+
viewport: Size,
|
|
65
|
+
options: PlacementOptions,
|
|
66
|
+
): Placement {
|
|
67
|
+
const { side, align, gap, edge, rtl, fitHeight, minHeight } = options;
|
|
68
|
+
const alignEnd = (align === "end") !== rtl;
|
|
69
|
+
|
|
70
|
+
/** The cross-axis offset: centred, or against one edge of the anchor. */
|
|
71
|
+
const across = (start: number, length: number, extent: number) =>
|
|
72
|
+
align === "center"
|
|
73
|
+
? start + (length - extent) / 2
|
|
74
|
+
: alignEnd
|
|
75
|
+
? start + length - extent
|
|
76
|
+
: start;
|
|
77
|
+
|
|
78
|
+
if (side === "top" || side === "bottom") {
|
|
79
|
+
const roomBelow = viewport.height - anchor.bottom - gap - edge;
|
|
80
|
+
const roomAbove = anchor.top - gap - edge;
|
|
81
|
+
const prefersBelow = side === "bottom";
|
|
82
|
+
const roomPreferred = prefersBelow ? roomBelow : roomAbove;
|
|
83
|
+
const roomOther = prefersBelow ? roomAbove : roomBelow;
|
|
84
|
+
|
|
85
|
+
const flip =
|
|
86
|
+
size.height > roomPreferred &&
|
|
87
|
+
(fitHeight ? roomOther > roomPreferred : size.height <= roomOther);
|
|
88
|
+
const below = prefersBelow !== flip;
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
side: below ? "bottom" : "top",
|
|
92
|
+
left: clamp(
|
|
93
|
+
across(anchor.left, anchor.width, size.width),
|
|
94
|
+
edge,
|
|
95
|
+
viewport.width - size.width - edge,
|
|
96
|
+
),
|
|
97
|
+
top: Math.max(edge, below ? anchor.bottom + gap : anchor.top - gap - size.height),
|
|
98
|
+
maxHeight: fitHeight
|
|
99
|
+
? Math.max(minHeight, below ? roomBelow : roomAbove)
|
|
100
|
+
: undefined,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const roomRight = viewport.width - anchor.right - gap - edge;
|
|
105
|
+
const roomLeft = anchor.left - gap - edge;
|
|
106
|
+
const prefersRight = (side === "right") !== rtl;
|
|
107
|
+
const roomPreferred = prefersRight ? roomRight : roomLeft;
|
|
108
|
+
const roomOther = prefersRight ? roomLeft : roomRight;
|
|
109
|
+
|
|
110
|
+
// Sideways there is nothing to scroll, so it only moves when it fully fits.
|
|
111
|
+
const flip = size.width > roomPreferred && size.width <= roomOther;
|
|
112
|
+
const right = prefersRight !== flip;
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
side: right ? "right" : "left",
|
|
116
|
+
left: Math.max(edge, right ? anchor.right + gap : anchor.left - gap - size.width),
|
|
117
|
+
top: clamp(
|
|
118
|
+
across(anchor.top, anchor.height, size.height),
|
|
119
|
+
edge,
|
|
120
|
+
viewport.height - size.height - edge,
|
|
121
|
+
),
|
|
122
|
+
maxHeight: fitHeight ? Math.max(minHeight, viewport.height - 2 * edge) : undefined,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
let segmenter: Intl.Segmenter | null | undefined;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Characters as a person counts them. `"👍🏽".length` is 4 and `"é"` can be 2,
|
|
5
|
+
* but each is one character here. Falls back to code points where
|
|
6
|
+
* `Intl.Segmenter` is missing.
|
|
7
|
+
*/
|
|
8
|
+
export function countCharacters(value: string): number {
|
|
9
|
+
if (!value) return 0;
|
|
10
|
+
if (segmenter === undefined) {
|
|
11
|
+
segmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter() : null;
|
|
12
|
+
}
|
|
13
|
+
return segmenter ? Array.from(segmenter.segment(value)).length : Array.from(value).length;
|
|
14
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { cx } from "./core/cx";
|
|
2
|
+
export { countCharacters } from "./core/text";
|
|
3
|
+
export { describeField, type DescribedByParts } from "./core/field";
|
|
4
|
+
export { useControllableState } from "./react/useControllableState";
|
|
5
|
+
export { AnchoredPopover, type AnchoredPopoverProps } from "./react/Popover";
|
|
6
|
+
export { placePopover, type Align, type Placement, type Side } from "./core/position";
|
|
7
|
+
export * as icons from "./react/icons";
|
|
8
|
+
export { version as sharedVersion } from "./version";
|
|
9
|
+
|
|
10
|
+
// Agent runtime: the component-agnostic operation/validation/history layer.
|
|
11
|
+
export * from "./core/agent";
|
|
12
|
+
export {
|
|
13
|
+
GramproAIProvider,
|
|
14
|
+
useAgentAdapter,
|
|
15
|
+
type GramproAIProviderProps,
|
|
16
|
+
} from "./react/GramproAIProvider";
|
|
17
|
+
export { useAskAgent, type AskableAgent, type AskExecution, type UseAskAgent } from "./react/useAskAgent";
|