@grampro/kit 0.0.0-stage → 2.4.0
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 +139 -0
- package/LICENSE +15 -0
- package/README.md +193 -2
- package/index.cjs +1370 -0
- package/package.json +74 -4
- 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,50 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext, useMemo, type ReactNode } from "react";
|
|
4
|
+
import type { AgentAdapter } from "../core/agent/adapter";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Where an application plugs its own language model in.
|
|
8
|
+
*
|
|
9
|
+
* Nothing below this provider knows which one it is. A component asks the
|
|
10
|
+
* context for an adapter; if there is none, the component renders exactly as
|
|
11
|
+
* it does today and its natural-language affordance is simply absent. That is
|
|
12
|
+
* the whole opt-in: no provider, no AI, no bytes, no network.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface AIContextValue {
|
|
16
|
+
adapter: AgentAdapter | null;
|
|
17
|
+
/** Shown above the input, e.g. "Ask about these customers". */
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
/** Example utterances offered as one-click suggestions. */
|
|
20
|
+
suggestions?: readonly string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const AIContext = createContext<AIContextValue>({ adapter: null });
|
|
24
|
+
|
|
25
|
+
export interface GramproAIProviderProps extends AIContextValue {
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function GramproAIProvider({
|
|
30
|
+
adapter,
|
|
31
|
+
placeholder,
|
|
32
|
+
suggestions,
|
|
33
|
+
children,
|
|
34
|
+
}: GramproAIProviderProps) {
|
|
35
|
+
const value = useMemo(
|
|
36
|
+
() => ({ adapter, placeholder, suggestions }),
|
|
37
|
+
[adapter, placeholder, suggestions],
|
|
38
|
+
);
|
|
39
|
+
return <AIContext.Provider value={value}>{children}</AIContext.Provider>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The adapter in scope, or null.
|
|
44
|
+
*
|
|
45
|
+
* Null is an ordinary case, not an error: a component asks, gets nothing, and
|
|
46
|
+
* renders without the affordance.
|
|
47
|
+
*/
|
|
48
|
+
export function useAgentAdapter(): AIContextValue {
|
|
49
|
+
return useContext(AIContext);
|
|
50
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useLayoutEffect, useRef, type ReactNode, type ToggleEvent } from "react";
|
|
4
|
+
import { cx } from "../core/cx";
|
|
5
|
+
import { placePopover, type Align, type Side } from "../core/position";
|
|
6
|
+
|
|
7
|
+
/** Space kept between the popover and the edge of the viewport. */
|
|
8
|
+
const EDGE = 8;
|
|
9
|
+
|
|
10
|
+
export interface AnchoredPopoverProps {
|
|
11
|
+
/** The element the popover is positioned against. */
|
|
12
|
+
anchor: HTMLElement;
|
|
13
|
+
/** Called when the browser light-dismisses it, or Escape closes it. */
|
|
14
|
+
onClose(): void;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
id?: string;
|
|
17
|
+
className?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Gives the popover `role="dialog"` and this accessible name. Leave it and
|
|
20
|
+
* `labelledBy` out for content that carries its own role, such as a listbox.
|
|
21
|
+
*/
|
|
22
|
+
label?: string;
|
|
23
|
+
/** Names the popover from an element inside it, such as its heading. */
|
|
24
|
+
labelledBy?: string;
|
|
25
|
+
/** Points at a description inside the popover. */
|
|
26
|
+
describedBy?: string;
|
|
27
|
+
/** `menu` for a list of commands, `tooltip` for a label; otherwise a dialog. */
|
|
28
|
+
role?: "dialog" | "menu" | "tooltip";
|
|
29
|
+
/** The side of the anchor to open on, before flipping. Default `bottom`. */
|
|
30
|
+
side?: Side;
|
|
31
|
+
/** Which edge of the anchor to align to, in reading order. Default `start`. */
|
|
32
|
+
align?: Align;
|
|
33
|
+
/** Distance between the anchor and the popover. Default 4. */
|
|
34
|
+
gap?: number;
|
|
35
|
+
/** Make the popover at least as wide as its anchor. */
|
|
36
|
+
matchAnchorWidth?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Cap the height to the free space on the chosen side, and prefer the side
|
|
39
|
+
* with more room. For scrolling content such as a long list; panels that
|
|
40
|
+
* cannot scroll should leave it off so they only flip when they fully fit.
|
|
41
|
+
*/
|
|
42
|
+
fitHeight?: boolean;
|
|
43
|
+
/** Floor for `fitHeight`, so a cramped viewport still shows something. Default 140. */
|
|
44
|
+
minHeight?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Where focus goes when it opens: a selector, `true` for the first
|
|
47
|
+
* `[data-autofocus]` and otherwise the popover itself, or `false` to leave
|
|
48
|
+
* focus where it is. A popover focused this way needs `tabIndex={-1}`.
|
|
49
|
+
*/
|
|
50
|
+
autoFocus?: string | boolean;
|
|
51
|
+
/** Reposition when the popover resizes (`self`) or the anchor does too (`both`). */
|
|
52
|
+
observeResize?: "self" | "both" | false;
|
|
53
|
+
/** Put focus back on the anchor when the popover closes. */
|
|
54
|
+
returnFocus?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* `auto` (the default) gets the browser's light dismiss and Escape, and is
|
|
57
|
+
* right for anything opened deliberately. `manual` opts out of both, for
|
|
58
|
+
* content that appears beside something else and must not close it: opening
|
|
59
|
+
* an `auto` popover closes every other one, so a tooltip or a submenu over an
|
|
60
|
+
* open menu would take the menu down with it. Manual popovers handle their
|
|
61
|
+
* own dismissal.
|
|
62
|
+
*/
|
|
63
|
+
mode?: "auto" | "manual";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Anchored popover on the native Popover API: rendered in the top layer, so it
|
|
68
|
+
* is never clipped by a scrolling parent or an `overflow: hidden` ancestor, and
|
|
69
|
+
* the browser provides light dismiss and Escape. Mount it to open, unmount it
|
|
70
|
+
* to close.
|
|
71
|
+
*
|
|
72
|
+
* Positioning is deliberately plain — align, clamp to the viewport, flip when
|
|
73
|
+
* there is no room below — because that is all any of the components need, and
|
|
74
|
+
* it keeps the library free of a positioning dependency.
|
|
75
|
+
*/
|
|
76
|
+
export function AnchoredPopover({
|
|
77
|
+
anchor,
|
|
78
|
+
onClose,
|
|
79
|
+
children,
|
|
80
|
+
id,
|
|
81
|
+
className,
|
|
82
|
+
label,
|
|
83
|
+
labelledBy,
|
|
84
|
+
describedBy,
|
|
85
|
+
role,
|
|
86
|
+
side = "bottom",
|
|
87
|
+
align = "start",
|
|
88
|
+
gap = 4,
|
|
89
|
+
matchAnchorWidth = false,
|
|
90
|
+
fitHeight = false,
|
|
91
|
+
minHeight = 140,
|
|
92
|
+
autoFocus = "[data-autofocus]",
|
|
93
|
+
observeResize = false,
|
|
94
|
+
returnFocus = false,
|
|
95
|
+
mode = "auto",
|
|
96
|
+
}: AnchoredPopoverProps) {
|
|
97
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
98
|
+
|
|
99
|
+
useLayoutEffect(() => {
|
|
100
|
+
const el = ref.current;
|
|
101
|
+
if (!el) return;
|
|
102
|
+
|
|
103
|
+
const position = () => {
|
|
104
|
+
const rect = anchor.getBoundingClientRect();
|
|
105
|
+
if (matchAnchorWidth) el.style.minWidth = `${rect.width}px`;
|
|
106
|
+
|
|
107
|
+
const placement = placePopover(
|
|
108
|
+
rect,
|
|
109
|
+
{ width: el.offsetWidth, height: el.offsetHeight },
|
|
110
|
+
{ width: window.innerWidth, height: window.innerHeight },
|
|
111
|
+
{
|
|
112
|
+
side,
|
|
113
|
+
align,
|
|
114
|
+
gap,
|
|
115
|
+
edge: EDGE,
|
|
116
|
+
rtl: getComputedStyle(anchor).direction === "rtl",
|
|
117
|
+
fitHeight,
|
|
118
|
+
minHeight,
|
|
119
|
+
},
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
el.style.left = `${placement.left}px`;
|
|
123
|
+
el.style.top = `${placement.top}px`;
|
|
124
|
+
if (placement.maxHeight !== undefined) el.style.maxHeight = `${placement.maxHeight}px`;
|
|
125
|
+
// Lets a stylesheet point an arrow, or slide the panel in from the right
|
|
126
|
+
// direction, without measuring anything itself.
|
|
127
|
+
el.dataset.side = placement.side;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
el.showPopover();
|
|
131
|
+
position();
|
|
132
|
+
// A popover is display:none until it is shown, so focus only lands after
|
|
133
|
+
// showPopover().
|
|
134
|
+
if (autoFocus) {
|
|
135
|
+
const selector = typeof autoFocus === "string" ? autoFocus : "[data-autofocus]";
|
|
136
|
+
const target = el.querySelector<HTMLElement>(selector) ?? (autoFocus === true ? el : null);
|
|
137
|
+
target?.focus({ preventScroll: true });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const observer = observeResize ? new ResizeObserver(position) : null;
|
|
141
|
+
observer?.observe(el);
|
|
142
|
+
if (observeResize === "both") observer?.observe(anchor);
|
|
143
|
+
window.addEventListener("resize", position);
|
|
144
|
+
// Capture: a scroll in any ancestor moves the anchor, not just the page.
|
|
145
|
+
window.addEventListener("scroll", position, true);
|
|
146
|
+
|
|
147
|
+
return () => {
|
|
148
|
+
observer?.disconnect();
|
|
149
|
+
window.removeEventListener("resize", position);
|
|
150
|
+
window.removeEventListener("scroll", position, true);
|
|
151
|
+
const hadFocus = el.contains(document.activeElement);
|
|
152
|
+
if (el.matches(":popover-open")) el.hidePopover();
|
|
153
|
+
if (returnFocus && (hadFocus || document.activeElement === document.body) && anchor.isConnected) {
|
|
154
|
+
anchor.focus({ preventScroll: true });
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}, [
|
|
158
|
+
anchor,
|
|
159
|
+
side,
|
|
160
|
+
align,
|
|
161
|
+
gap,
|
|
162
|
+
matchAnchorWidth,
|
|
163
|
+
fitHeight,
|
|
164
|
+
minHeight,
|
|
165
|
+
autoFocus,
|
|
166
|
+
observeResize,
|
|
167
|
+
returnFocus,
|
|
168
|
+
]);
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<div
|
|
172
|
+
ref={ref}
|
|
173
|
+
id={id}
|
|
174
|
+
popover={mode}
|
|
175
|
+
// Focusable only from script, so `autoFocus` can land on the panel itself.
|
|
176
|
+
tabIndex={-1}
|
|
177
|
+
role={role ?? (label || labelledBy ? "dialog" : undefined)}
|
|
178
|
+
aria-label={label}
|
|
179
|
+
aria-labelledby={labelledBy}
|
|
180
|
+
aria-describedby={describedBy}
|
|
181
|
+
className={cx(className)}
|
|
182
|
+
onToggle={(event: ToggleEvent<HTMLDivElement>) => {
|
|
183
|
+
if (event.newState === "closed") onClose();
|
|
184
|
+
}}
|
|
185
|
+
>
|
|
186
|
+
{children}
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { SVGProps } from "react";
|
|
2
|
+
|
|
3
|
+
export type IconProps = SVGProps<SVGSVGElement>;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The base every icon draws on: a 24-unit grid, stroked in `currentColor`, and
|
|
7
|
+
* hidden from assistive technology because the control around it carries the
|
|
8
|
+
* name. Size it by passing `width` and `height`.
|
|
9
|
+
*/
|
|
10
|
+
export function Svg(props: IconProps) {
|
|
11
|
+
return (
|
|
12
|
+
<svg
|
|
13
|
+
width="16"
|
|
14
|
+
height="16"
|
|
15
|
+
viewBox="0 0 24 24"
|
|
16
|
+
fill="none"
|
|
17
|
+
stroke="currentColor"
|
|
18
|
+
strokeWidth="2"
|
|
19
|
+
strokeLinecap="round"
|
|
20
|
+
strokeLinejoin="round"
|
|
21
|
+
aria-hidden="true"
|
|
22
|
+
focusable="false"
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* Glyphs more than one component draws. A component keeps its own icons file
|
|
30
|
+
* for anything only it uses, and re-exports from here for the rest, so a fix to
|
|
31
|
+
* a shape lands everywhere at once.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
export const XIcon = (p: IconProps) => <Svg {...p}><path d="M18 6 6 18M6 6l12 12" /></Svg>;
|
|
35
|
+
export const CheckIcon = (p: IconProps) => <Svg {...p}><path d="M20 6 9 17l-5-5" /></Svg>;
|
|
36
|
+
export const ChevronDownIcon = (p: IconProps) => <Svg {...p}><path d="m6 9 6 6 6-6" /></Svg>;
|
|
37
|
+
export const ChevronLeftIcon = (p: IconProps) => <Svg {...p}><path d="m15 18-6-6 6-6" /></Svg>;
|
|
38
|
+
export const ChevronRightIcon = (p: IconProps) => <Svg {...p}><path d="m9 18 6-6-6-6" /></Svg>;
|
|
39
|
+
|
|
40
|
+
export const SearchIcon = (p: IconProps) => (
|
|
41
|
+
<Svg {...p}><circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" /></Svg>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export const SuccessIcon = (p: IconProps) => (
|
|
45
|
+
<Svg {...p}>
|
|
46
|
+
<circle cx="12" cy="12" r="9" />
|
|
47
|
+
<path d="m8 12.5 2.5 2.5L16 9.5" />
|
|
48
|
+
</Svg>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
/** The circled exclamation used for errors, danger and alerts alike. */
|
|
52
|
+
export const AlertCircleIcon = (p: IconProps) => (
|
|
53
|
+
<Svg {...p}>
|
|
54
|
+
<circle cx="12" cy="12" r="9" />
|
|
55
|
+
<path d="M12 7.5v5.5M12 16.5h.01" />
|
|
56
|
+
</Svg>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
export const WarningIcon = (p: IconProps) => (
|
|
60
|
+
<Svg {...p}>
|
|
61
|
+
<path d="M10.3 3.9 2.4 18a2 2 0 0 0 1.7 3h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z" />
|
|
62
|
+
<path d="M12 9v4M12 17h.01" />
|
|
63
|
+
</Svg>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
export const InfoIcon = (p: IconProps) => (
|
|
67
|
+
<Svg {...p}>
|
|
68
|
+
<circle cx="12" cy="12" r="9" />
|
|
69
|
+
<path d="M12 11v5M12 7.5h.01" />
|
|
70
|
+
</Svg>
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
/** The arc only; the spin comes from each component's own stylesheet. */
|
|
74
|
+
export const SpinnerIcon = (p: IconProps) => <Svg {...p}><path d="M12 3a9 9 0 1 0 9 9" /></Svg>;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import type { AgentAdapter, AskOutcome } from "../core/agent/adapter";
|
|
5
|
+
import type { JsonSchema } from "../core/agent/types";
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* One request, end to end: what a person typed goes to the adapter, the
|
|
9
|
+
* adapter's answer goes to the validator, and only a validated command runs.
|
|
10
|
+
*
|
|
11
|
+
* The order is the point. This hook never looks at the answer's contents to
|
|
12
|
+
* decide anything — it hands the envelope to `respond()` and reports what came
|
|
13
|
+
* back. A producer that returns nonsense, a stale schema, or an operation the
|
|
14
|
+
* component does not have is refused by the same five layers a form faces, and
|
|
15
|
+
* the person sees the validator's own words rather than a guess.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** The part of a component's agent this hook uses. */
|
|
19
|
+
export interface AskableAgent {
|
|
20
|
+
contract(): unknown;
|
|
21
|
+
responseSchema(): JsonSchema;
|
|
22
|
+
/** Validates a whole envelope. Does not change anything. */
|
|
23
|
+
respond(response: unknown): AskExecution;
|
|
24
|
+
execute(intent: unknown, options?: { confirm?: boolean }): Promise<AskExecution>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The statuses a component's validator and executor answer with. */
|
|
28
|
+
export type AskExecution =
|
|
29
|
+
| {
|
|
30
|
+
status: "done";
|
|
31
|
+
commands: readonly { explain: { summary: string } }[];
|
|
32
|
+
warnings: readonly { code: string; message: string }[];
|
|
33
|
+
}
|
|
34
|
+
| {
|
|
35
|
+
status: "needs-confirmation";
|
|
36
|
+
commands: readonly { explain: { summary: string } }[];
|
|
37
|
+
confirm: { code: string; message: string };
|
|
38
|
+
}
|
|
39
|
+
| { status: "rejected"; reason: string; code: string; layer: string; suggestion?: string }
|
|
40
|
+
| { status: "clarify"; question: string; options?: readonly string[] }
|
|
41
|
+
| { status: "declined"; reason: string };
|
|
42
|
+
|
|
43
|
+
const IDLE: AskOutcome = { phase: "idle", message: "" };
|
|
44
|
+
|
|
45
|
+
export interface UseAskAgent {
|
|
46
|
+
ask(utterance: string): Promise<void>;
|
|
47
|
+
/** Run a `needs-confirmation` request the person has now agreed to. */
|
|
48
|
+
confirm(): Promise<void>;
|
|
49
|
+
reset(): void;
|
|
50
|
+
outcome: AskOutcome;
|
|
51
|
+
busy: boolean;
|
|
52
|
+
/** Set when the last answer stopped to ask; `confirm()` applies it. */
|
|
53
|
+
pending: unknown;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function useAskAgent(
|
|
57
|
+
agent: AskableAgent | null,
|
|
58
|
+
adapter: AgentAdapter | null,
|
|
59
|
+
): UseAskAgent {
|
|
60
|
+
const [outcome, setOutcome] = useState<AskOutcome>(IDLE);
|
|
61
|
+
const [busy, setBusy] = useState(false);
|
|
62
|
+
const [pending, setPending] = useState<unknown>(null);
|
|
63
|
+
|
|
64
|
+
// One request at a time: typing again abandons the one in flight rather
|
|
65
|
+
// than racing it to the grid.
|
|
66
|
+
const inFlight = useRef<AbortController | null>(null);
|
|
67
|
+
const alive = useRef(true);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
alive.current = true;
|
|
70
|
+
return () => {
|
|
71
|
+
alive.current = false;
|
|
72
|
+
inFlight.current?.abort();
|
|
73
|
+
};
|
|
74
|
+
}, []);
|
|
75
|
+
|
|
76
|
+
const report = useCallback((next: AskOutcome) => {
|
|
77
|
+
if (alive.current) setOutcome(next);
|
|
78
|
+
}, []);
|
|
79
|
+
|
|
80
|
+
/** Turn a validator answer into something to show, and run it when allowed. */
|
|
81
|
+
const settle = useCallback(
|
|
82
|
+
async (verdict: AskExecution, intents: unknown, raw: unknown) => {
|
|
83
|
+
if (verdict.status === "rejected") {
|
|
84
|
+
report({
|
|
85
|
+
phase: "refused",
|
|
86
|
+
message: verdict.reason,
|
|
87
|
+
code: verdict.code,
|
|
88
|
+
layer: verdict.layer,
|
|
89
|
+
suggestion: verdict.suggestion,
|
|
90
|
+
raw,
|
|
91
|
+
});
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (verdict.status === "clarify") {
|
|
95
|
+
report({ phase: "clarify", message: verdict.question, raw });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (verdict.status === "declined") {
|
|
99
|
+
report({ phase: "refused", message: verdict.reason, raw });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (verdict.status === "needs-confirmation") {
|
|
103
|
+
setPending(intents);
|
|
104
|
+
report({
|
|
105
|
+
phase: "clarify",
|
|
106
|
+
message: verdict.confirm.message,
|
|
107
|
+
code: verdict.confirm.code,
|
|
108
|
+
raw,
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const run = await agent!.execute(intents);
|
|
114
|
+
if (run.status !== "done") {
|
|
115
|
+
report({
|
|
116
|
+
phase: "refused",
|
|
117
|
+
message: "reason" in run ? run.reason : run.status,
|
|
118
|
+
raw,
|
|
119
|
+
});
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
report({
|
|
123
|
+
phase: "done",
|
|
124
|
+
message: run.commands.map((command) => command.explain.summary).join("; "),
|
|
125
|
+
warnings: run.warnings.map((warning) => `${warning.code}: ${warning.message}`),
|
|
126
|
+
raw,
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
[agent, report],
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const ask = useCallback(
|
|
133
|
+
async (utterance: string) => {
|
|
134
|
+
const text = utterance.trim();
|
|
135
|
+
if (!agent || !adapter || text === "") return;
|
|
136
|
+
|
|
137
|
+
inFlight.current?.abort();
|
|
138
|
+
const controller = new AbortController();
|
|
139
|
+
inFlight.current = controller;
|
|
140
|
+
|
|
141
|
+
setPending(null);
|
|
142
|
+
setBusy(true);
|
|
143
|
+
report({ phase: "thinking", message: "" });
|
|
144
|
+
|
|
145
|
+
let raw: unknown;
|
|
146
|
+
try {
|
|
147
|
+
raw = await adapter({
|
|
148
|
+
utterance: text,
|
|
149
|
+
contract: agent.contract(),
|
|
150
|
+
responseSchema: agent.responseSchema(),
|
|
151
|
+
signal: controller.signal,
|
|
152
|
+
});
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (!controller.signal.aborted) {
|
|
155
|
+
// Reaching the producer failed. That is not the producer refusing,
|
|
156
|
+
// and saying so avoids blaming the person's wording.
|
|
157
|
+
report({
|
|
158
|
+
phase: "error",
|
|
159
|
+
message: error instanceof Error ? error.message : String(error),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (alive.current && inFlight.current === controller) setBusy(false);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (controller.signal.aborted) return;
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
const intents =
|
|
170
|
+
raw && typeof raw === "object" && "intents" in raw
|
|
171
|
+
? (raw as { intents: unknown }).intents
|
|
172
|
+
: raw;
|
|
173
|
+
await settle(agent.respond(raw), intents, raw);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
report({
|
|
176
|
+
phase: "error",
|
|
177
|
+
message: error instanceof Error ? error.message : String(error),
|
|
178
|
+
raw,
|
|
179
|
+
});
|
|
180
|
+
} finally {
|
|
181
|
+
if (alive.current && inFlight.current === controller) setBusy(false);
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
[adapter, agent, report, settle],
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const confirm = useCallback(async () => {
|
|
188
|
+
if (!agent || pending === null) return;
|
|
189
|
+
setBusy(true);
|
|
190
|
+
try {
|
|
191
|
+
// Without the flag the executor stops and asks again, forever.
|
|
192
|
+
const run = await agent.execute(pending, { confirm: true });
|
|
193
|
+
report(
|
|
194
|
+
run.status === "done"
|
|
195
|
+
? {
|
|
196
|
+
phase: "done",
|
|
197
|
+
message: run.commands.map((command) => command.explain.summary).join("; "),
|
|
198
|
+
}
|
|
199
|
+
: {
|
|
200
|
+
phase: "refused",
|
|
201
|
+
message: "reason" in run ? run.reason : run.status,
|
|
202
|
+
},
|
|
203
|
+
);
|
|
204
|
+
setPending(null);
|
|
205
|
+
} finally {
|
|
206
|
+
if (alive.current) setBusy(false);
|
|
207
|
+
}
|
|
208
|
+
}, [agent, pending, report]);
|
|
209
|
+
|
|
210
|
+
const reset = useCallback(() => {
|
|
211
|
+
inFlight.current?.abort();
|
|
212
|
+
setPending(null);
|
|
213
|
+
report(IDLE);
|
|
214
|
+
}, [report]);
|
|
215
|
+
|
|
216
|
+
return { ask, confirm, reset, outcome, busy, pending };
|
|
217
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* One value that may be controlled by the caller or owned by the component.
|
|
7
|
+
*
|
|
8
|
+
* Pass the `value` prop (or `undefined`) and the `defaultValue`. The returned
|
|
9
|
+
* setter writes internal state only while the component is uncontrolled, so a
|
|
10
|
+
* controlled caller stays the single source of truth and the component never
|
|
11
|
+
* renders a value its parent did not hand it.
|
|
12
|
+
*
|
|
13
|
+
* Change callbacks stay with the component: they differ too much between
|
|
14
|
+
* controls — some pass a DOM event, some skip a no-op change — and hiding them
|
|
15
|
+
* here would only move the difference somewhere less obvious.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* const [value, setValue] = useControllableState(valueProp, defaultValue ?? "");
|
|
19
|
+
*
|
|
20
|
+
* const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
21
|
+
* setValue(event.target.value);
|
|
22
|
+
* onChange?.(event);
|
|
23
|
+
* };
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function useControllableState<T>(
|
|
27
|
+
controlled: T | undefined,
|
|
28
|
+
defaultValue: T | (() => T),
|
|
29
|
+
): readonly [T, (next: T) => void, boolean] {
|
|
30
|
+
const [internal, setInternal] = useState(defaultValue);
|
|
31
|
+
const isControlled = controlled !== undefined;
|
|
32
|
+
const value = isControlled ? controlled : internal;
|
|
33
|
+
|
|
34
|
+
const setValue = useCallback(
|
|
35
|
+
(next: T) => {
|
|
36
|
+
if (!isControlled) setInternal(next);
|
|
37
|
+
},
|
|
38
|
+
[isControlled],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return [value, setValue, isControlled] as const;
|
|
42
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Shared defaults every component can rely on.
|
|
3
|
+
*
|
|
4
|
+
* Rules are unlayered: they beat a framework reset on specificity, and lose to
|
|
5
|
+
* anything you pass through `className`. With Tailwind v4, import this file
|
|
6
|
+
* after the framework and inside its components layer - see the README.
|
|
7
|
+
*
|
|
8
|
+
* Right now this file is scrollbars. Each component carries its own fallback
|
|
9
|
+
* values, so a component installed on its own still looks right; what lives
|
|
10
|
+
* here is the single place to theme them, and the `gbs-scroll` class for your
|
|
11
|
+
* own scrolling areas.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* Thin scrollbars, themed with the rest of the kit.
|
|
16
|
+
*
|
|
17
|
+
* `scrollbar-width` and `scrollbar-color` are the standard properties -
|
|
18
|
+
* Baseline since December 2024 - rather than the `::-webkit-scrollbar`
|
|
19
|
+
* pseudo-elements. Two reasons: the standard ones are what the other browsers
|
|
20
|
+
* implement, and mixing the two is a known way to get a scrollbar that is thin
|
|
21
|
+
* in one engine and default in another. `scrollbar-width` takes no length,
|
|
22
|
+
* only `auto | thin | none`, so `thin` is the whole control surface.
|
|
23
|
+
*
|
|
24
|
+
* Override any of these on `:root` to restyle every scrollbar at once, or on
|
|
25
|
+
* one element to restyle that one:
|
|
26
|
+
*
|
|
27
|
+
* :root {
|
|
28
|
+
* --gbs-scrollbar-width: auto; bring the chunky ones back
|
|
29
|
+
* --gbs-scrollbar-thumb: var(--gbs-accent); tint them with the brand
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
:root {
|
|
33
|
+
/* `auto | thin | none`. `thin` is the default across the kit. */
|
|
34
|
+
--gbs-scrollbar-width: thin;
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
* Derived from the accent so a themed kit themes its scrollbars too, and
|
|
38
|
+
* muted hard, because a scrollbar is furniture rather than content. The
|
|
39
|
+
* fallbacks are the same neutral the components use when untouched.
|
|
40
|
+
*/
|
|
41
|
+
--gbs-scrollbar-thumb: color-mix(
|
|
42
|
+
in oklab,
|
|
43
|
+
var(--gbs-accent, light-dark(#2563eb, #60a5fa)) 28%,
|
|
44
|
+
light-dark(#a1a1aa, #52525b)
|
|
45
|
+
);
|
|
46
|
+
--gbs-scrollbar-thumb-hover: color-mix(
|
|
47
|
+
in oklab,
|
|
48
|
+
var(--gbs-accent, light-dark(#2563eb, #60a5fa)) 55%,
|
|
49
|
+
light-dark(#71717a, #71717a)
|
|
50
|
+
);
|
|
51
|
+
/* Transparent by default: a track that is a visible stripe reads as heavier
|
|
52
|
+
than the scrollbar it holds. */
|
|
53
|
+
--gbs-scrollbar-track: transparent;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* Apply to your own scrolling areas to match the components:
|
|
58
|
+
*
|
|
59
|
+
* <div class="gbs-scroll">…</div>
|
|
60
|
+
*
|
|
61
|
+
* `:where()` keeps the specificity at zero, so a single utility class of your
|
|
62
|
+
* own still wins without `!important`.
|
|
63
|
+
*/
|
|
64
|
+
:where(.gbs-scroll) {
|
|
65
|
+
scrollbar-width: var(--gbs-scrollbar-width, thin);
|
|
66
|
+
scrollbar-color: var(--gbs-scrollbar-thumb, light-dark(#c4c4ca, #3f3f46))
|
|
67
|
+
var(--gbs-scrollbar-track, transparent);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
* The hover brightening is a progressive enhancement: `scrollbar-color` does
|
|
72
|
+
* not transition, and a pointer-coarse device has no hover to speak of.
|
|
73
|
+
*/
|
|
74
|
+
@media (hover: hover) {
|
|
75
|
+
:where(.gbs-scroll):hover {
|
|
76
|
+
scrollbar-color: var(--gbs-scrollbar-thumb-hover, light-dark(#a1a1aa, #52525b))
|
|
77
|
+
var(--gbs-scrollbar-track, transparent);
|
|
78
|
+
}
|
|
79
|
+
}
|