@tai42/studio-sdk 0.2.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/LICENSE +202 -0
- package/NOTICE +15 -0
- package/README.md +318 -0
- package/SECURITY.md +51 -0
- package/dist/components/badge.d.ts +13 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.js +14 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/checkbox.d.ts +24 -0
- package/dist/components/checkbox.d.ts.map +1 -0
- package/dist/components/checkbox.js +31 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/code-block.d.ts +7 -0
- package/dist/components/code-block.d.ts.map +1 -0
- package/dist/components/code-block.js +23 -0
- package/dist/components/code-block.js.map +1 -0
- package/dist/components/completion-input.d.ts +31 -0
- package/dist/components/completion-input.d.ts.map +1 -0
- package/dist/components/completion-input.js +61 -0
- package/dist/components/completion-input.js.map +1 -0
- package/dist/components/components.css +2212 -0
- package/dist/components/confirm-dialog.d.ts +40 -0
- package/dist/components/confirm-dialog.d.ts.map +1 -0
- package/dist/components/confirm-dialog.js +11 -0
- package/dist/components/confirm-dialog.js.map +1 -0
- package/dist/components/control-styles.d.ts +12 -0
- package/dist/components/control-styles.d.ts.map +1 -0
- package/dist/components/control-styles.js +14 -0
- package/dist/components/control-styles.js.map +1 -0
- package/dist/components/copy-field.d.ts +8 -0
- package/dist/components/copy-field.d.ts.map +1 -0
- package/dist/components/copy-field.js +106 -0
- package/dist/components/copy-field.js.map +1 -0
- package/dist/components/dialog.d.ts +21 -0
- package/dist/components/dialog.d.ts.map +1 -0
- package/dist/components/dialog.js +25 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/drawer.d.ts +22 -0
- package/dist/components/drawer.d.ts.map +1 -0
- package/dist/components/drawer.js +32 -0
- package/dist/components/drawer.js.map +1 -0
- package/dist/components/error-boundary.d.ts +33 -0
- package/dist/components/error-boundary.d.ts.map +1 -0
- package/dist/components/error-boundary.js +36 -0
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/components/extension-combo-builder.d.ts +70 -0
- package/dist/components/extension-combo-builder.d.ts.map +1 -0
- package/dist/components/extension-combo-builder.js +154 -0
- package/dist/components/extension-combo-builder.js.map +1 -0
- package/dist/components/extension-grouping.d.ts +65 -0
- package/dist/components/extension-grouping.d.ts.map +1 -0
- package/dist/components/extension-grouping.js +78 -0
- package/dist/components/extension-grouping.js.map +1 -0
- package/dist/components/extension-picker.d.ts +35 -0
- package/dist/components/extension-picker.d.ts.map +1 -0
- package/dist/components/extension-picker.js +31 -0
- package/dist/components/extension-picker.js.map +1 -0
- package/dist/components/external-link.d.ts +19 -0
- package/dist/components/external-link.d.ts.map +1 -0
- package/dist/components/external-link.js +12 -0
- package/dist/components/external-link.js.map +1 -0
- package/dist/components/field.d.ts +64 -0
- package/dist/components/field.d.ts.map +1 -0
- package/dist/components/field.js +56 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/fleet-report.d.ts +39 -0
- package/dist/components/fleet-report.d.ts.map +1 -0
- package/dist/components/fleet-report.js +50 -0
- package/dist/components/fleet-report.js.map +1 -0
- package/dist/components/fonts.css +22 -0
- package/dist/components/icons.d.ts +142 -0
- package/dist/components/icons.d.ts.map +1 -0
- package/dist/components/icons.js +139 -0
- package/dist/components/icons.js.map +1 -0
- package/dist/components/inputs.d.ts +52 -0
- package/dist/components/inputs.d.ts.map +1 -0
- package/dist/components/inputs.js +35 -0
- package/dist/components/inputs.js.map +1 -0
- package/dist/components/json-diff.d.ts +40 -0
- package/dist/components/json-diff.d.ts.map +1 -0
- package/dist/components/json-diff.js +119 -0
- package/dist/components/json-diff.js.map +1 -0
- package/dist/components/json-tree.d.ts +8 -0
- package/dist/components/json-tree.d.ts.map +1 -0
- package/dist/components/json-tree.js +70 -0
- package/dist/components/json-tree.js.map +1 -0
- package/dist/components/modal-focus.d.ts +15 -0
- package/dist/components/modal-focus.d.ts.map +1 -0
- package/dist/components/modal-focus.js +136 -0
- package/dist/components/modal-focus.js.map +1 -0
- package/dist/components/page-header.d.ts +56 -0
- package/dist/components/page-header.d.ts.map +1 -0
- package/dist/components/page-header.js +24 -0
- package/dist/components/page-header.js.map +1 -0
- package/dist/components/primitives.d.ts +186 -0
- package/dist/components/primitives.d.ts.map +1 -0
- package/dist/components/primitives.js +204 -0
- package/dist/components/primitives.js.map +1 -0
- package/dist/components/progress-bar.d.ts +29 -0
- package/dist/components/progress-bar.d.ts.map +1 -0
- package/dist/components/progress-bar.js +48 -0
- package/dist/components/progress-bar.js.map +1 -0
- package/dist/components/radio-group.d.ts +37 -0
- package/dist/components/radio-group.d.ts.map +1 -0
- package/dist/components/radio-group.js +56 -0
- package/dist/components/radio-group.js.map +1 -0
- package/dist/components/reveal-input.d.ts +13 -0
- package/dist/components/reveal-input.d.ts.map +1 -0
- package/dist/components/reveal-input.js +31 -0
- package/dist/components/reveal-input.js.map +1 -0
- package/dist/components/scroll-region.d.ts +85 -0
- package/dist/components/scroll-region.d.ts.map +1 -0
- package/dist/components/scroll-region.js +574 -0
- package/dist/components/scroll-region.js.map +1 -0
- package/dist/components/select.d.ts +53 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.js +33 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/table.d.ts +59 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/table.js +20 -0
- package/dist/components/table.js.map +1 -0
- package/dist/components/tabs.d.ts +15 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/tabs.js +13 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/tags.d.ts +46 -0
- package/dist/components/tags.d.ts.map +1 -0
- package/dist/components/tags.js +68 -0
- package/dist/components/tags.js.map +1 -0
- package/dist/components/tokens.css +392 -0
- package/dist/components/tokens.d.ts +15 -0
- package/dist/components/tokens.d.ts.map +1 -0
- package/dist/components/tokens.js +101 -0
- package/dist/components/tokens.js.map +1 -0
- package/dist/components/tool-picker.d.ts +24 -0
- package/dist/components/tool-picker.d.ts.map +1 -0
- package/dist/components/tool-picker.js +97 -0
- package/dist/components/tool-picker.js.map +1 -0
- package/dist/components/tooltip.d.ts +17 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip.js +18 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/components/version-history-panel.d.ts +71 -0
- package/dist/components/version-history-panel.d.ts.map +1 -0
- package/dist/components/version-history-panel.js +148 -0
- package/dist/components/version-history-panel.js.map +1 -0
- package/dist/download.d.ts +7 -0
- package/dist/download.d.ts.map +1 -0
- package/dist/download.js +18 -0
- package/dist/download.js.map +1 -0
- package/dist/element-slot.d.ts +4 -0
- package/dist/element-slot.d.ts.map +1 -0
- package/dist/element-slot.js +20 -0
- package/dist/element-slot.js.map +1 -0
- package/dist/elicitation/ElicitationForm.d.ts +34 -0
- package/dist/elicitation/ElicitationForm.d.ts.map +1 -0
- package/dist/elicitation/ElicitationForm.js +24 -0
- package/dist/elicitation/ElicitationForm.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -0
- package/dist/extension-combos.d.ts +13 -0
- package/dist/extension-combos.d.ts.map +1 -0
- package/dist/extension-combos.js +9 -0
- package/dist/extension-combos.js.map +1 -0
- package/dist/hooks/useApi.d.ts +1222 -0
- package/dist/hooks/useApi.d.ts.map +1 -0
- package/dist/hooks/useApi.js +22 -0
- package/dist/hooks/useApi.js.map +1 -0
- package/dist/hooks/useAuth.d.ts +13 -0
- package/dist/hooks/useAuth.d.ts.map +1 -0
- package/dist/hooks/useAuth.js +53 -0
- package/dist/hooks/useAuth.js.map +1 -0
- package/dist/hooks/useBreakpoint.d.ts +10 -0
- package/dist/hooks/useBreakpoint.d.ts.map +1 -0
- package/dist/hooks/useBreakpoint.js +66 -0
- package/dist/hooks/useBreakpoint.js.map +1 -0
- package/dist/hooks/useCapabilities.d.ts +88 -0
- package/dist/hooks/useCapabilities.d.ts.map +1 -0
- package/dist/hooks/useCapabilities.js +203 -0
- package/dist/hooks/useCapabilities.js.map +1 -0
- package/dist/hooks/useSse.d.ts +13 -0
- package/dist/hooks/useSse.d.ts.map +1 -0
- package/dist/hooks/useSse.js +298 -0
- package/dist/hooks/useSse.js.map +1 -0
- package/dist/hooks/useTheme.d.ts +20 -0
- package/dist/hooks/useTheme.d.ts.map +1 -0
- package/dist/hooks/useTheme.js +97 -0
- package/dist/hooks/useTheme.js.map +1 -0
- package/dist/hooks/useUnauthorized.d.ts +3 -0
- package/dist/hooks/useUnauthorized.d.ts.map +1 -0
- package/dist/hooks/useUnauthorized.js +18 -0
- package/dist/hooks/useUnauthorized.js.map +1 -0
- package/dist/host.d.ts +11 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +10 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation/context.d.ts +25 -0
- package/dist/navigation/context.d.ts.map +1 -0
- package/dist/navigation/context.js +45 -0
- package/dist/navigation/context.js.map +1 -0
- package/dist/navigation/index.d.ts +4 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +2 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/types.d.ts +97 -0
- package/dist/navigation/types.d.ts.map +1 -0
- package/dist/navigation/types.js +16 -0
- package/dist/navigation/types.js.map +1 -0
- package/dist/plugin/host-state.d.ts +45 -0
- package/dist/plugin/host-state.d.ts.map +1 -0
- package/dist/plugin/host-state.js +62 -0
- package/dist/plugin/host-state.js.map +1 -0
- package/dist/plugin/registry.d.ts +35 -0
- package/dist/plugin/registry.d.ts.map +1 -0
- package/dist/plugin/registry.js +129 -0
- package/dist/plugin/registry.js.map +1 -0
- package/dist/plugin/types.d.ts +165 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/plugin/types.js +2 -0
- package/dist/plugin/types.js.map +1 -0
- package/dist/plugin/version.d.ts +34 -0
- package/dist/plugin/version.d.ts.map +1 -0
- package/dist/plugin/version.js +37 -0
- package/dist/plugin/version.js.map +1 -0
- package/dist/query-keys.d.ts +31 -0
- package/dist/query-keys.d.ts.map +1 -0
- package/dist/query-keys.js +31 -0
- package/dist/query-keys.js.map +1 -0
- package/dist/schema-editor/SchemaEditor.d.ts +43 -0
- package/dist/schema-editor/SchemaEditor.d.ts.map +1 -0
- package/dist/schema-editor/SchemaEditor.js +106 -0
- package/dist/schema-editor/SchemaEditor.js.map +1 -0
- package/dist/schema-editor/index.d.ts +10 -0
- package/dist/schema-editor/index.d.ts.map +1 -0
- package/dist/schema-editor/index.js +8 -0
- package/dist/schema-editor/index.js.map +1 -0
- package/dist/schema-editor/lint.d.ts +37 -0
- package/dist/schema-editor/lint.d.ts.map +1 -0
- package/dist/schema-editor/lint.js +49 -0
- package/dist/schema-editor/lint.js.map +1 -0
- package/dist/schema-form/SchemaForm.d.ts +70 -0
- package/dist/schema-form/SchemaForm.d.ts.map +1 -0
- package/dist/schema-form/SchemaForm.js +13 -0
- package/dist/schema-form/SchemaForm.js.map +1 -0
- package/dist/schema-form/array-field.d.ts +20 -0
- package/dist/schema-form/array-field.d.ts.map +1 -0
- package/dist/schema-form/array-field.js +39 -0
- package/dist/schema-form/array-field.js.map +1 -0
- package/dist/schema-form/classify.d.ts +87 -0
- package/dist/schema-form/classify.d.ts.map +1 -0
- package/dist/schema-form/classify.js +199 -0
- package/dist/schema-form/classify.js.map +1 -0
- package/dist/schema-form/context.d.ts +4 -0
- package/dist/schema-form/context.d.ts.map +1 -0
- package/dist/schema-form/context.js +14 -0
- package/dist/schema-form/context.js.map +1 -0
- package/dist/schema-form/default-value.d.ts +8 -0
- package/dist/schema-form/default-value.d.ts.map +1 -0
- package/dist/schema-form/default-value.js +64 -0
- package/dist/schema-form/default-value.js.map +1 -0
- package/dist/schema-form/enum-field.d.ts +19 -0
- package/dist/schema-form/enum-field.d.ts.map +1 -0
- package/dist/schema-form/enum-field.js +26 -0
- package/dist/schema-form/enum-field.js.map +1 -0
- package/dist/schema-form/field-group.d.ts +9 -0
- package/dist/schema-form/field-group.d.ts.map +1 -0
- package/dist/schema-form/field-group.js +32 -0
- package/dist/schema-form/field-group.js.map +1 -0
- package/dist/schema-form/field-node.d.ts +24 -0
- package/dist/schema-form/field-node.d.ts.map +1 -0
- package/dist/schema-form/field-node.js +51 -0
- package/dist/schema-form/field-node.js.map +1 -0
- package/dist/schema-form/index.d.ts +13 -0
- package/dist/schema-form/index.d.ts.map +1 -0
- package/dist/schema-form/index.js +11 -0
- package/dist/schema-form/index.js.map +1 -0
- package/dist/schema-form/media-field.d.ts +24 -0
- package/dist/schema-form/media-field.d.ts.map +1 -0
- package/dist/schema-form/media-field.js +169 -0
- package/dist/schema-form/media-field.js.map +1 -0
- package/dist/schema-form/media.d.ts +40 -0
- package/dist/schema-form/media.d.ts.map +1 -0
- package/dist/schema-form/media.js +65 -0
- package/dist/schema-form/media.js.map +1 -0
- package/dist/schema-form/object-fields.d.ts +20 -0
- package/dist/schema-form/object-fields.d.ts.map +1 -0
- package/dist/schema-form/object-fields.js +24 -0
- package/dist/schema-form/object-fields.js.map +1 -0
- package/dist/schema-form/resolve.d.ts +41 -0
- package/dist/schema-form/resolve.d.ts.map +1 -0
- package/dist/schema-form/resolve.js +102 -0
- package/dist/schema-form/resolve.js.map +1 -0
- package/dist/schema-form/string-field.d.ts +20 -0
- package/dist/schema-form/string-field.d.ts.map +1 -0
- package/dist/schema-form/string-field.js +68 -0
- package/dist/schema-form/string-field.js.map +1 -0
- package/dist/schema-form/styles.d.ts +18 -0
- package/dist/schema-form/styles.d.ts.map +1 -0
- package/dist/schema-form/styles.js +18 -0
- package/dist/schema-form/styles.js.map +1 -0
- package/dist/schema-form/types.d.ts +67 -0
- package/dist/schema-form/types.d.ts.map +1 -0
- package/dist/schema-form/types.js +10 -0
- package/dist/schema-form/types.js.map +1 -0
- package/dist/schema-form/union-field.d.ts +24 -0
- package/dist/schema-form/union-field.d.ts.map +1 -0
- package/dist/schema-form/union-field.js +55 -0
- package/dist/schema-form/union-field.js.map +1 -0
- package/dist/schema-form/union.d.ts +4 -0
- package/dist/schema-form/union.d.ts.map +1 -0
- package/dist/schema-form/union.js +68 -0
- package/dist/schema-form/union.js.map +1 -0
- package/dist/schema-form/unsupported-notice.d.ts +18 -0
- package/dist/schema-form/unsupported-notice.d.ts.map +1 -0
- package/dist/schema-form/unsupported-notice.js +8 -0
- package/dist/schema-form/unsupported-notice.js.map +1 -0
- package/dist/schema-form/validate.d.ts +18 -0
- package/dist/schema-form/validate.d.ts.map +1 -0
- package/dist/schema-form/validate.js +162 -0
- package/dist/schema-form/validate.js.map +1 -0
- package/dist/structured-output/StructuredOutput.d.ts +27 -0
- package/dist/structured-output/StructuredOutput.d.ts.map +1 -0
- package/dist/structured-output/StructuredOutput.js +41 -0
- package/dist/structured-output/StructuredOutput.js.map +1 -0
- package/dist/testing.d.ts +80 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +207 -0
- package/dist/testing.js.map +1 -0
- package/package.json +101 -0
- package/src/components/badge.tsx +31 -0
- package/src/components/checkbox.tsx +93 -0
- package/src/components/code-block.tsx +37 -0
- package/src/components/completion-input.tsx +137 -0
- package/src/components/components.css +2212 -0
- package/src/components/confirm-dialog.tsx +77 -0
- package/src/components/control-styles.ts +14 -0
- package/src/components/copy-field.tsx +178 -0
- package/src/components/dialog.tsx +76 -0
- package/src/components/drawer.tsx +83 -0
- package/src/components/error-boundary.tsx +56 -0
- package/src/components/extension-combo-builder.tsx +305 -0
- package/src/components/extension-grouping.ts +116 -0
- package/src/components/extension-picker.tsx +97 -0
- package/src/components/external-link.tsx +40 -0
- package/src/components/field.tsx +169 -0
- package/src/components/fleet-report.tsx +136 -0
- package/src/components/fonts.css +22 -0
- package/src/components/icons.tsx +504 -0
- package/src/components/inputs.tsx +125 -0
- package/src/components/json-diff.tsx +192 -0
- package/src/components/json-tree.tsx +129 -0
- package/src/components/modal-focus.ts +150 -0
- package/src/components/page-header.tsx +107 -0
- package/src/components/primitives.tsx +489 -0
- package/src/components/progress-bar.tsx +100 -0
- package/src/components/radio-group.tsx +160 -0
- package/src/components/reveal-input.tsx +87 -0
- package/src/components/scroll-region.tsx +703 -0
- package/src/components/select.tsx +149 -0
- package/src/components/table.tsx +94 -0
- package/src/components/tabs.tsx +51 -0
- package/src/components/tags.tsx +137 -0
- package/src/components/tokens.css +392 -0
- package/src/components/tokens.ts +102 -0
- package/src/components/tool-picker.tsx +175 -0
- package/src/components/tooltip.tsx +46 -0
- package/src/components/version-history-panel.tsx +407 -0
- package/src/css.d.ts +2 -0
- package/src/download.ts +17 -0
- package/src/element-slot.ts +22 -0
- package/src/elicitation/ElicitationForm.tsx +87 -0
- package/src/errors.ts +12 -0
- package/src/extension-combos.ts +18 -0
- package/src/hooks/useApi.ts +27 -0
- package/src/hooks/useAuth.ts +67 -0
- package/src/hooks/useBreakpoint.ts +78 -0
- package/src/hooks/useCapabilities.ts +242 -0
- package/src/hooks/useSse.ts +314 -0
- package/src/hooks/useTheme.ts +133 -0
- package/src/hooks/useUnauthorized.ts +20 -0
- package/src/host.ts +15 -0
- package/src/index.ts +267 -0
- package/src/navigation/context.tsx +90 -0
- package/src/navigation/index.ts +9 -0
- package/src/navigation/types.ts +90 -0
- package/src/plugin/host-state.ts +93 -0
- package/src/plugin/registry.ts +174 -0
- package/src/plugin/types.ts +178 -0
- package/src/plugin/version.ts +44 -0
- package/src/query-keys.ts +34 -0
- package/src/schema-editor/SchemaEditor.tsx +186 -0
- package/src/schema-editor/index.ts +9 -0
- package/src/schema-editor/lint.ts +70 -0
- package/src/schema-form/SchemaForm.tsx +107 -0
- package/src/schema-form/array-field.tsx +110 -0
- package/src/schema-form/classify.ts +302 -0
- package/src/schema-form/context.ts +17 -0
- package/src/schema-form/default-value.ts +65 -0
- package/src/schema-form/enum-field.tsx +65 -0
- package/src/schema-form/field-group.tsx +71 -0
- package/src/schema-form/field-node.tsx +161 -0
- package/src/schema-form/index.ts +12 -0
- package/src/schema-form/media-field.tsx +281 -0
- package/src/schema-form/media.ts +69 -0
- package/src/schema-form/object-fields.tsx +74 -0
- package/src/schema-form/resolve.ts +114 -0
- package/src/schema-form/string-field.tsx +161 -0
- package/src/schema-form/styles.ts +20 -0
- package/src/schema-form/types.ts +71 -0
- package/src/schema-form/union-field.tsx +122 -0
- package/src/schema-form/union.ts +78 -0
- package/src/schema-form/unsupported-notice.tsx +39 -0
- package/src/schema-form/validate.ts +183 -0
- package/src/structured-output/StructuredOutput.tsx +81 -0
- package/src/testing.ts +235 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The design-system token contract: colors, spacing, typography, radii, motion,
|
|
3
|
+
* elevation, and the z-scale, all as CSS variables. This ships as PRECOMPILED CSS
|
|
4
|
+
* with preflight disabled (the SHELL owns preflight). Plugins style via these
|
|
5
|
+
* tokens + SDK components ONLY.
|
|
6
|
+
*
|
|
7
|
+
* CASCADE ORDER. This file is the canonical layer-order emitter and loads FIRST.
|
|
8
|
+
* The host's reset/`base` layer is ordered BEFORE the design-system layers so a
|
|
9
|
+
* preflight that zeroes borders and heading typography cannot erase a DS
|
|
10
|
+
* component class; the host's own utility layers are declared afterwards and so
|
|
11
|
+
* sort AFTER `tai-utilities`, keeping host utilities the final word over DS
|
|
12
|
+
* component styles.
|
|
13
|
+
*
|
|
14
|
+
* THEMING. The light value is the token; the dark value sits beside it under a
|
|
15
|
+
* `--tai-dark-` name. Each colour is therefore still written exactly once, and
|
|
16
|
+
* the two blocks that apply the dark half carry no values of their own — they
|
|
17
|
+
* only re-point each token at its `--tai-dark-*` neighbour, so a light and dark
|
|
18
|
+
* pair cannot drift apart. A `data-theme` pin on the root decides the theme in
|
|
19
|
+
* BOTH directions — the media query stands down for a root pinned to light, and
|
|
20
|
+
* the pinned-dark block applies the same set outright — so `prefers-color-scheme`
|
|
21
|
+
* is the DEFAULT only for a root that carries no pin. In `apps/studio` that
|
|
22
|
+
* window is the first paint: `ThemeProvider` (`useTheme`) stamps `data-theme` on
|
|
23
|
+
* mount, after which the media query no longer decides and an OS theme flip
|
|
24
|
+
* while the app is open changes nothing. Following the OS live — a `matchMedia`
|
|
25
|
+
* listener and a `system` preference — belongs to the host's theme provider, not
|
|
26
|
+
* to this sheet. A host that mounts no provider keeps the media query as its
|
|
27
|
+
* theme source. `color-scheme` follows the same three states, so native scrollbars,
|
|
28
|
+
* selects and form autofill match the tokens.
|
|
29
|
+
*
|
|
30
|
+
* BROWSER FLOOR. Deliberately NOT `light-dark()`. That function would fold each
|
|
31
|
+
* pair onto one line, but it is invalid at computed-value time below Chrome 123 /
|
|
32
|
+
* Firefox 120 / Safari 17.5 — and because every themed token would use it, the
|
|
33
|
+
* whole palette drops out at once below that line, leaving text on text rather
|
|
34
|
+
* than an unstyled page. These sheets ship as authored (the SDK build is `tsc`
|
|
35
|
+
* plus a copy, so nothing lowers them), so what they ask for IS the floor: the
|
|
36
|
+
* highest thing here is `@layer` and `:focus-visible`, at Chrome/Edge 99,
|
|
37
|
+
* Firefox 97, and Safari / iOS Safari 15.4. That floor is declared in this
|
|
38
|
+
* package's `browserslist` rather than left implicit, and the token scanner test
|
|
39
|
+
* bans `light-dark()` so it cannot be raised back by accident. (The SHELL app
|
|
40
|
+
* sits higher — it compiles Tailwind v4, whose own output needs `@property` and
|
|
41
|
+
* `color-mix()` — and declares that floor in the repo root's `browserslist`.)
|
|
42
|
+
*
|
|
43
|
+
* UNITS. Type and spacing tokens are authored in rem so a viewer's font-size
|
|
44
|
+
* preference scales them; radius, elevation, and z tokens stay px/unitless. The
|
|
45
|
+
* comment beside each type/space token is its rendered px at a 16 px root.
|
|
46
|
+
* Line-height and weight are NOT baked into these tokens — the component classes
|
|
47
|
+
* own them, so a `font:` shorthand never resets them.
|
|
48
|
+
*/
|
|
49
|
+
@layer theme, base, tai-tokens, tai-components, tai-utilities;
|
|
50
|
+
|
|
51
|
+
@keyframes tai-spin {
|
|
52
|
+
to {
|
|
53
|
+
transform: rotate(360deg);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Loading skeleton: a raised band sweeps across the LINE-tone ground the block
|
|
58
|
+
rests at, which is what makes a placeholder read as pending rather than as
|
|
59
|
+
empty content. The band is an OVERLAY (`.tai-skeleton::after` in
|
|
60
|
+
`components.css`) travelling on `transform`, so the block itself never moves
|
|
61
|
+
and the browser can carry the sweep on the compositor instead of restyling
|
|
62
|
+
and repainting every skeleton on the page each frame. */
|
|
63
|
+
@keyframes tai-shimmer {
|
|
64
|
+
from {
|
|
65
|
+
transform: translateX(-100%);
|
|
66
|
+
}
|
|
67
|
+
to {
|
|
68
|
+
transform: translateX(100%);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Indeterminate progress: a short fill sweeps across the track when a running
|
|
73
|
+
tool reports progress but no total is known. */
|
|
74
|
+
@keyframes tai-progress-indeterminate {
|
|
75
|
+
0% {
|
|
76
|
+
transform: translateX(-100%);
|
|
77
|
+
}
|
|
78
|
+
100% {
|
|
79
|
+
transform: translateX(320%);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@layer tai-tokens {
|
|
84
|
+
:root {
|
|
85
|
+
/* The OS preference is the default theme source; the data-theme blocks
|
|
86
|
+
below pin it. */
|
|
87
|
+
color-scheme: light dark;
|
|
88
|
+
|
|
89
|
+
/* Every colour below carries the LIGHT value; the `--tai-dark-` line beside
|
|
90
|
+
it carries the dark one. Nothing else in the repo writes either — the two
|
|
91
|
+
blocks further down only re-point a token at its dark neighbour. */
|
|
92
|
+
|
|
93
|
+
/* -- Grounds ---------------------------------------------------------- */
|
|
94
|
+
--tai-color-bg: #ffffff;
|
|
95
|
+
--tai-dark-color-bg: #0c0e12;
|
|
96
|
+
--tai-color-surface: #f9fafb;
|
|
97
|
+
--tai-dark-color-surface: #12151b;
|
|
98
|
+
--tai-color-surface-raised: #ffffff;
|
|
99
|
+
--tai-dark-color-surface-raised: #171c24;
|
|
100
|
+
--tai-color-surface-disabled: var(--tai-color-surface);
|
|
101
|
+
--tai-color-code-bg: #f3f4f6;
|
|
102
|
+
--tai-dark-color-code-bg: #10131a;
|
|
103
|
+
|
|
104
|
+
/* -- Lines ------------------------------------------------------------
|
|
105
|
+
`border` and `border-strong` are decorative: they are below 3:1 and may
|
|
106
|
+
never be a control's only boundary. `control-border` is the contrast-safe
|
|
107
|
+
boundary for inputs, checkboxes, and secondary buttons. */
|
|
108
|
+
--tai-color-border: #e5e7eb;
|
|
109
|
+
--tai-dark-color-border: #262c36;
|
|
110
|
+
--tai-color-border-strong: #d1d5db;
|
|
111
|
+
--tai-dark-color-border-strong: #39414e;
|
|
112
|
+
--tai-color-control-border: #767c85;
|
|
113
|
+
--tai-dark-color-control-border: #646c79;
|
|
114
|
+
--tai-color-border-disabled: var(--tai-color-border);
|
|
115
|
+
|
|
116
|
+
/* -- Ink ---------------------------------------------------------------
|
|
117
|
+
`decor` is the NON-TEXT tier (dividers, watermarks, decorative SVG fill
|
|
118
|
+
or stroke). It never appears on `color:` and never identifies a component
|
|
119
|
+
or a state. */
|
|
120
|
+
--tai-color-text: #111827;
|
|
121
|
+
--tai-dark-color-text: #e6e8ec;
|
|
122
|
+
--tai-color-heading: #000000;
|
|
123
|
+
--tai-dark-color-heading: #ffffff;
|
|
124
|
+
--tai-color-text-muted: rgba(17, 24, 39, 0.62);
|
|
125
|
+
--tai-dark-color-text-muted: rgba(230, 232, 236, 0.64);
|
|
126
|
+
--tai-color-text-disabled: rgba(17, 24, 39, 0.38);
|
|
127
|
+
--tai-dark-color-text-disabled: rgba(230, 232, 236, 0.36);
|
|
128
|
+
--tai-color-placeholder: var(--tai-color-text-muted);
|
|
129
|
+
--tai-color-decor: rgba(17, 24, 39, 0.44);
|
|
130
|
+
--tai-dark-color-decor: rgba(230, 232, 236, 0.42);
|
|
131
|
+
|
|
132
|
+
/* -- Accent (crimson) --------------------------------------------------
|
|
133
|
+
The accent is brand, never status. `accent-hover` darkens in light and
|
|
134
|
+
LIGHTENS in dark. `accent-on-tint` is accent TEXT sitting on accent-tint;
|
|
135
|
+
`on-accent` is the label on an accent FILL. */
|
|
136
|
+
--tai-color-accent: #dc143c;
|
|
137
|
+
--tai-dark-color-accent: #ed4c67;
|
|
138
|
+
--tai-color-accent-hover: #800020;
|
|
139
|
+
--tai-dark-color-accent-hover: #f4718a;
|
|
140
|
+
--tai-color-accent-on-tint: #be123c;
|
|
141
|
+
--tai-dark-color-accent-on-tint: #f4718a;
|
|
142
|
+
--tai-color-on-accent: #ffffff;
|
|
143
|
+
--tai-dark-color-on-accent: #0c0e12;
|
|
144
|
+
--tai-color-accent-tint: rgba(220, 20, 60, 0.08);
|
|
145
|
+
--tai-dark-color-accent-tint: rgba(237, 76, 103, 0.12);
|
|
146
|
+
|
|
147
|
+
/* -- Semantic ----------------------------------------------------------
|
|
148
|
+
The `-text` members are the ONLY ones legible as text, dots, or icons;
|
|
149
|
+
the `-fill` members are for fills and charts and carry `on-fill` ink
|
|
150
|
+
labels in both themes. */
|
|
151
|
+
--tai-color-ok-text: #047857;
|
|
152
|
+
--tai-dark-color-ok-text: #34d399;
|
|
153
|
+
--tai-color-err-text: #b91c1c;
|
|
154
|
+
--tai-dark-color-err-text: #f87171;
|
|
155
|
+
--tai-color-warn-text: #92400e;
|
|
156
|
+
--tai-dark-color-warn-text: #fbbf24;
|
|
157
|
+
--tai-color-ok-fill: #10b981;
|
|
158
|
+
--tai-dark-color-ok-fill: #34d399;
|
|
159
|
+
--tai-color-err-fill: #ef4444;
|
|
160
|
+
--tai-dark-color-err-fill: #f87171;
|
|
161
|
+
--tai-color-warn-fill: #d97706;
|
|
162
|
+
--tai-dark-color-warn-fill: #fbbf24;
|
|
163
|
+
--tai-color-ok-tint: rgba(16, 185, 129, 0.1);
|
|
164
|
+
--tai-dark-color-ok-tint: rgba(52, 211, 153, 0.12);
|
|
165
|
+
--tai-color-err-tint: rgba(239, 68, 68, 0.1);
|
|
166
|
+
--tai-dark-color-err-tint: rgba(248, 113, 113, 0.12);
|
|
167
|
+
--tai-color-warn-tint: rgba(217, 119, 6, 0.1);
|
|
168
|
+
--tai-dark-color-warn-tint: rgba(251, 191, 36, 0.12);
|
|
169
|
+
/* The one ink deliberately identical in both themes: every semantic fill is
|
|
170
|
+
light enough that only the dark label clears the contrast floor on it. */
|
|
171
|
+
--tai-color-on-fill: #0c0e12;
|
|
172
|
+
|
|
173
|
+
/* -- Focus + overlay ----------------------------------------------------
|
|
174
|
+
The ring is an ALIAS, not a restatement: it IS the accent, so referencing
|
|
175
|
+
it keeps two values that must move together from drifting apart, and it
|
|
176
|
+
needs no dark half of its own. */
|
|
177
|
+
--tai-color-focus-ring: var(--tai-color-accent);
|
|
178
|
+
--tai-color-scrim: rgba(0, 0, 0, 0.45);
|
|
179
|
+
--tai-dark-color-scrim: rgba(0, 0, 0, 0.6);
|
|
180
|
+
|
|
181
|
+
/* -- Prose --------------------------------------------------------------
|
|
182
|
+
A prose link is always underlined, so colour is a reinforcement rather
|
|
183
|
+
than the only cue. Dark rest is the LIGHTER crimson: the light-theme
|
|
184
|
+
accent is too dim against a dark ground, and the hover value is the
|
|
185
|
+
legible one there (6.17 on raised). Hover then moves to the other member
|
|
186
|
+
in both themes. Spelled out rather than aliased — the two halves of each
|
|
187
|
+
pair come from different members of the accent ramp. */
|
|
188
|
+
--tai-color-prose-link: #dc143c;
|
|
189
|
+
--tai-dark-color-prose-link: #f4718a;
|
|
190
|
+
--tai-color-prose-link-hover: #800020;
|
|
191
|
+
--tai-dark-color-prose-link-hover: #ed4c67;
|
|
192
|
+
|
|
193
|
+
/* -- Syntax (JSON/code on code-bg) -------------------------------------- */
|
|
194
|
+
--tai-color-syntax-key: var(--tai-color-text-muted);
|
|
195
|
+
--tai-color-syntax-string: var(--tai-color-ok-text);
|
|
196
|
+
--tai-color-syntax-number: var(--tai-color-accent);
|
|
197
|
+
--tai-color-syntax-bool: var(--tai-color-warn-text);
|
|
198
|
+
|
|
199
|
+
/* -- Legacy token slots -------------------------------------------------
|
|
200
|
+
The names a plugin already styles against, re-pointed at the members of
|
|
201
|
+
the contract above that keep them legible. `danger-text` is the label on
|
|
202
|
+
the danger FILL, so it is white in light and ink in dark. */
|
|
203
|
+
--tai-color-primary: var(--tai-color-accent);
|
|
204
|
+
--tai-color-primary-text: var(--tai-color-on-accent);
|
|
205
|
+
--tai-color-danger: var(--tai-color-err-text);
|
|
206
|
+
--tai-color-danger-text: #ffffff;
|
|
207
|
+
--tai-dark-color-danger-text: #0c0e12;
|
|
208
|
+
--tai-color-danger-hover: #7f1d1d;
|
|
209
|
+
--tai-dark-color-danger-hover: #fca5a5;
|
|
210
|
+
--tai-color-danger-surface: var(--tai-color-err-tint);
|
|
211
|
+
--tai-color-success: var(--tai-color-ok-text);
|
|
212
|
+
--tai-color-warning: var(--tai-color-warn-text);
|
|
213
|
+
|
|
214
|
+
/* -- Spacing (n x 4; there is deliberately no space-7) ------------------ */
|
|
215
|
+
--tai-space-1: 0.25rem; /* 4px */
|
|
216
|
+
--tai-space-2: 0.5rem; /* 8px */
|
|
217
|
+
--tai-space-3: 0.75rem; /* 12px */
|
|
218
|
+
--tai-space-4: 1rem; /* 16px */
|
|
219
|
+
--tai-space-5: 1.25rem; /* 20px */
|
|
220
|
+
--tai-space-6: 1.5rem; /* 24px */
|
|
221
|
+
--tai-space-8: 2rem; /* 32px */
|
|
222
|
+
|
|
223
|
+
/* -- Radius ------------------------------------------------------------- */
|
|
224
|
+
--tai-radius-sm: 4px;
|
|
225
|
+
--tai-radius-code: 6px;
|
|
226
|
+
--tai-radius-md: 8px;
|
|
227
|
+
--tai-radius-tile: 10px;
|
|
228
|
+
--tai-radius-lg: 12px;
|
|
229
|
+
--tai-radius-overlay: 14px;
|
|
230
|
+
--tai-radius-full: 999px;
|
|
231
|
+
|
|
232
|
+
/* -- Type --------------------------------------------------------------- */
|
|
233
|
+
--tai-font-sans:
|
|
234
|
+
'Inter Variable', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
235
|
+
--tai-font-mono:
|
|
236
|
+
'Geist Mono Variable', ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, monospace;
|
|
237
|
+
--tai-text-display: 1.625rem; /* 26px — KPI numbers */
|
|
238
|
+
--tai-text-xl: 1.4375rem; /* 23px — page title */
|
|
239
|
+
--tai-text-section: 1.0625rem; /* 17px — section heading */
|
|
240
|
+
--tai-text-lg: 0.9375rem; /* 15px — card title */
|
|
241
|
+
--tai-text-md: 0.84375rem; /* 13.5px — body */
|
|
242
|
+
--tai-text-sm: 0.78125rem; /* 12.5px — secondary */
|
|
243
|
+
--tai-text-code: 0.75rem; /* 12px — mono blocks */
|
|
244
|
+
--tai-text-xs: 0.6875rem; /* 11px — labels, badges, axes (the floor) */
|
|
245
|
+
|
|
246
|
+
/* -- Control geometry ---------------------------------------------------
|
|
247
|
+
One height for every button, input, and select trigger; the coarse value
|
|
248
|
+
is the pointer-target minimum a touch device gets instead. */
|
|
249
|
+
--tai-control-height: 36px;
|
|
250
|
+
--tai-control-height-coarse: 44px;
|
|
251
|
+
|
|
252
|
+
/* -- Motion -------------------------------------------------------------- */
|
|
253
|
+
--tai-motion-fast: 150ms;
|
|
254
|
+
--tai-motion-base: 250ms;
|
|
255
|
+
|
|
256
|
+
/* -- Elevation ------------------------------------------------------------
|
|
257
|
+
Only the shadow COLOUR varies by theme; the geometry is written once, so a
|
|
258
|
+
dark override cannot silently move an offset or a blur. */
|
|
259
|
+
--tai-shadow-lift-color: rgb(0 0 0 / 0.08);
|
|
260
|
+
--tai-dark-shadow-lift-color: rgb(0 0 0 / 0.45);
|
|
261
|
+
--tai-shadow-overlay-color: rgb(0 0 0 / 0.16);
|
|
262
|
+
--tai-dark-shadow-overlay-color: rgb(0 0 0 / 0.6);
|
|
263
|
+
--tai-shadow-lift: 0 12px 32px var(--tai-shadow-lift-color);
|
|
264
|
+
--tai-shadow-overlay: 0 24px 48px var(--tai-shadow-overlay-color);
|
|
265
|
+
/* Legacy slots, re-pointed at the new elevation pair. Both names are kept
|
|
266
|
+
and both changed MEANING: they were resting shadows (`0 1px 2px` /
|
|
267
|
+
`0 4px 12px`) and now alias the lift and overlay geometry. */
|
|
268
|
+
--tai-shadow-sm: var(--tai-shadow-lift);
|
|
269
|
+
--tai-shadow-md: var(--tai-shadow-overlay);
|
|
270
|
+
|
|
271
|
+
/* -- Stacking ------------------------------------------------------------
|
|
272
|
+
`popover` and `tooltip` sit ABOVE the modal layers on purpose. Both are
|
|
273
|
+
portalled to the document body as siblings of a dialog, and both can only
|
|
274
|
+
be opened from whatever layer is on top — so a listbox or a tip raised
|
|
275
|
+
from inside a dialog has to clear that dialog's scrim to be usable.
|
|
276
|
+
`dropdown` is the rung reserved for an in-flow menu surface — one that
|
|
277
|
+
stacks against the page rather than being portalled. Nothing in this repo
|
|
278
|
+
is on it; it is part of the published scale so a plugin's own menu has a
|
|
279
|
+
rung to sit on instead of inventing a number. */
|
|
280
|
+
--tai-z-sticky: 10;
|
|
281
|
+
--tai-z-dropdown: 20;
|
|
282
|
+
--tai-z-overlay: 30;
|
|
283
|
+
--tai-z-dialog: 40;
|
|
284
|
+
--tai-z-popover: 45;
|
|
285
|
+
--tai-z-tooltip: 50;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/*
|
|
289
|
+
* THE DARK HALF, APPLIED. The next two blocks are the only places the dark
|
|
290
|
+
* values are put into service, and neither carries a value of its own: every
|
|
291
|
+
* line re-points a token at its `--tai-dark-*` neighbour above. The media query
|
|
292
|
+
* stands down for a root explicitly pinned to light, so the viewer's choice
|
|
293
|
+
* always wins over the operating system's. The token scanner test holds the two
|
|
294
|
+
* blocks to the same token set, so a token can never take the dark half under
|
|
295
|
+
* one of them and keep the light half under the other.
|
|
296
|
+
*/
|
|
297
|
+
@media (prefers-color-scheme: dark) {
|
|
298
|
+
:root:not([data-theme='light']) {
|
|
299
|
+
--tai-color-bg: var(--tai-dark-color-bg);
|
|
300
|
+
--tai-color-surface: var(--tai-dark-color-surface);
|
|
301
|
+
--tai-color-surface-raised: var(--tai-dark-color-surface-raised);
|
|
302
|
+
--tai-color-code-bg: var(--tai-dark-color-code-bg);
|
|
303
|
+
--tai-color-border: var(--tai-dark-color-border);
|
|
304
|
+
--tai-color-border-strong: var(--tai-dark-color-border-strong);
|
|
305
|
+
--tai-color-control-border: var(--tai-dark-color-control-border);
|
|
306
|
+
--tai-color-text: var(--tai-dark-color-text);
|
|
307
|
+
--tai-color-heading: var(--tai-dark-color-heading);
|
|
308
|
+
--tai-color-text-muted: var(--tai-dark-color-text-muted);
|
|
309
|
+
--tai-color-text-disabled: var(--tai-dark-color-text-disabled);
|
|
310
|
+
--tai-color-decor: var(--tai-dark-color-decor);
|
|
311
|
+
--tai-color-accent: var(--tai-dark-color-accent);
|
|
312
|
+
--tai-color-accent-hover: var(--tai-dark-color-accent-hover);
|
|
313
|
+
--tai-color-accent-on-tint: var(--tai-dark-color-accent-on-tint);
|
|
314
|
+
--tai-color-on-accent: var(--tai-dark-color-on-accent);
|
|
315
|
+
--tai-color-accent-tint: var(--tai-dark-color-accent-tint);
|
|
316
|
+
--tai-color-ok-text: var(--tai-dark-color-ok-text);
|
|
317
|
+
--tai-color-err-text: var(--tai-dark-color-err-text);
|
|
318
|
+
--tai-color-warn-text: var(--tai-dark-color-warn-text);
|
|
319
|
+
--tai-color-ok-fill: var(--tai-dark-color-ok-fill);
|
|
320
|
+
--tai-color-err-fill: var(--tai-dark-color-err-fill);
|
|
321
|
+
--tai-color-warn-fill: var(--tai-dark-color-warn-fill);
|
|
322
|
+
--tai-color-ok-tint: var(--tai-dark-color-ok-tint);
|
|
323
|
+
--tai-color-err-tint: var(--tai-dark-color-err-tint);
|
|
324
|
+
--tai-color-warn-tint: var(--tai-dark-color-warn-tint);
|
|
325
|
+
--tai-color-scrim: var(--tai-dark-color-scrim);
|
|
326
|
+
--tai-color-prose-link: var(--tai-dark-color-prose-link);
|
|
327
|
+
--tai-color-prose-link-hover: var(--tai-dark-color-prose-link-hover);
|
|
328
|
+
--tai-color-danger-text: var(--tai-dark-color-danger-text);
|
|
329
|
+
--tai-color-danger-hover: var(--tai-dark-color-danger-hover);
|
|
330
|
+
--tai-shadow-lift-color: var(--tai-dark-shadow-lift-color);
|
|
331
|
+
--tai-shadow-overlay-color: var(--tai-dark-shadow-overlay-color);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* The viewer's explicit toggle wins over the system preference, in BOTH
|
|
336
|
+
directions (data-theme is stamped on the root by useTheme). Pinning
|
|
337
|
+
`color-scheme` is what keeps native UI — scrollbars, selects, autofill — on
|
|
338
|
+
the same theme as the tokens. */
|
|
339
|
+
:root[data-theme='light'] {
|
|
340
|
+
color-scheme: light;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
:root[data-theme='dark'] {
|
|
344
|
+
color-scheme: dark;
|
|
345
|
+
--tai-color-bg: var(--tai-dark-color-bg);
|
|
346
|
+
--tai-color-surface: var(--tai-dark-color-surface);
|
|
347
|
+
--tai-color-surface-raised: var(--tai-dark-color-surface-raised);
|
|
348
|
+
--tai-color-code-bg: var(--tai-dark-color-code-bg);
|
|
349
|
+
--tai-color-border: var(--tai-dark-color-border);
|
|
350
|
+
--tai-color-border-strong: var(--tai-dark-color-border-strong);
|
|
351
|
+
--tai-color-control-border: var(--tai-dark-color-control-border);
|
|
352
|
+
--tai-color-text: var(--tai-dark-color-text);
|
|
353
|
+
--tai-color-heading: var(--tai-dark-color-heading);
|
|
354
|
+
--tai-color-text-muted: var(--tai-dark-color-text-muted);
|
|
355
|
+
--tai-color-text-disabled: var(--tai-dark-color-text-disabled);
|
|
356
|
+
--tai-color-decor: var(--tai-dark-color-decor);
|
|
357
|
+
--tai-color-accent: var(--tai-dark-color-accent);
|
|
358
|
+
--tai-color-accent-hover: var(--tai-dark-color-accent-hover);
|
|
359
|
+
--tai-color-accent-on-tint: var(--tai-dark-color-accent-on-tint);
|
|
360
|
+
--tai-color-on-accent: var(--tai-dark-color-on-accent);
|
|
361
|
+
--tai-color-accent-tint: var(--tai-dark-color-accent-tint);
|
|
362
|
+
--tai-color-ok-text: var(--tai-dark-color-ok-text);
|
|
363
|
+
--tai-color-err-text: var(--tai-dark-color-err-text);
|
|
364
|
+
--tai-color-warn-text: var(--tai-dark-color-warn-text);
|
|
365
|
+
--tai-color-ok-fill: var(--tai-dark-color-ok-fill);
|
|
366
|
+
--tai-color-err-fill: var(--tai-dark-color-err-fill);
|
|
367
|
+
--tai-color-warn-fill: var(--tai-dark-color-warn-fill);
|
|
368
|
+
--tai-color-ok-tint: var(--tai-dark-color-ok-tint);
|
|
369
|
+
--tai-color-err-tint: var(--tai-dark-color-err-tint);
|
|
370
|
+
--tai-color-warn-tint: var(--tai-dark-color-warn-tint);
|
|
371
|
+
--tai-color-scrim: var(--tai-dark-color-scrim);
|
|
372
|
+
--tai-color-prose-link: var(--tai-dark-color-prose-link);
|
|
373
|
+
--tai-color-prose-link-hover: var(--tai-dark-color-prose-link-hover);
|
|
374
|
+
--tai-color-danger-text: var(--tai-dark-color-danger-text);
|
|
375
|
+
--tai-color-danger-hover: var(--tai-dark-color-danger-hover);
|
|
376
|
+
--tai-shadow-lift-color: var(--tai-dark-shadow-lift-color);
|
|
377
|
+
--tai-shadow-overlay-color: var(--tai-dark-shadow-overlay-color);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/* The motion durations are published API: a plugin writes
|
|
381
|
+
`transition: … var(--tai-motion-fast)` against them and has no other way to
|
|
382
|
+
learn the viewer's preference. Zeroing them here honours that preference for
|
|
383
|
+
every consumer at once — this repo's classes, and code the design system
|
|
384
|
+
never sees. (The component layer additionally pins `transition: none` on its
|
|
385
|
+
own controls, which covers any that do not spell their duration as a token.) */
|
|
386
|
+
@media (prefers-reduced-motion: reduce) {
|
|
387
|
+
:root {
|
|
388
|
+
--tai-motion-fast: 0ms;
|
|
389
|
+
--tai-motion-base: 0ms;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The documented CSS-variable token names — the Studio-plugin styling API. A
|
|
3
|
+
* snapshot test pins this list so the contract can't drift silently. The
|
|
4
|
+
* SDK compatibility version bumps if any of these are renamed/removed; the list
|
|
5
|
+
* grows additively.
|
|
6
|
+
*
|
|
7
|
+
* The `--tai-dark-*` half of each themed pair is deliberately NOT here. Those
|
|
8
|
+
* names are the theming mechanism's own storage — the two blocks in `tokens.css`
|
|
9
|
+
* that apply the dark theme are the only readers, and the scanner test holds
|
|
10
|
+
* them to that. A plugin styles against the name WITHOUT the `dark` segment and
|
|
11
|
+
* gets whichever half the viewer's theme resolves to.
|
|
12
|
+
*/
|
|
13
|
+
export const TOKEN_NAMES = [
|
|
14
|
+
'--tai-color-bg',
|
|
15
|
+
'--tai-color-surface',
|
|
16
|
+
'--tai-color-surface-raised',
|
|
17
|
+
'--tai-color-surface-disabled',
|
|
18
|
+
'--tai-color-code-bg',
|
|
19
|
+
'--tai-color-border',
|
|
20
|
+
'--tai-color-border-strong',
|
|
21
|
+
'--tai-color-control-border',
|
|
22
|
+
'--tai-color-border-disabled',
|
|
23
|
+
'--tai-color-text',
|
|
24
|
+
'--tai-color-heading',
|
|
25
|
+
'--tai-color-text-muted',
|
|
26
|
+
'--tai-color-text-disabled',
|
|
27
|
+
'--tai-color-placeholder',
|
|
28
|
+
'--tai-color-decor',
|
|
29
|
+
'--tai-color-accent',
|
|
30
|
+
'--tai-color-accent-hover',
|
|
31
|
+
'--tai-color-accent-on-tint',
|
|
32
|
+
'--tai-color-on-accent',
|
|
33
|
+
'--tai-color-accent-tint',
|
|
34
|
+
'--tai-color-ok-text',
|
|
35
|
+
'--tai-color-err-text',
|
|
36
|
+
'--tai-color-warn-text',
|
|
37
|
+
'--tai-color-ok-fill',
|
|
38
|
+
'--tai-color-err-fill',
|
|
39
|
+
'--tai-color-warn-fill',
|
|
40
|
+
'--tai-color-ok-tint',
|
|
41
|
+
'--tai-color-err-tint',
|
|
42
|
+
'--tai-color-warn-tint',
|
|
43
|
+
'--tai-color-on-fill',
|
|
44
|
+
'--tai-color-focus-ring',
|
|
45
|
+
'--tai-color-scrim',
|
|
46
|
+
'--tai-color-prose-link',
|
|
47
|
+
'--tai-color-prose-link-hover',
|
|
48
|
+
'--tai-color-syntax-key',
|
|
49
|
+
'--tai-color-syntax-string',
|
|
50
|
+
'--tai-color-syntax-number',
|
|
51
|
+
'--tai-color-syntax-bool',
|
|
52
|
+
'--tai-color-primary',
|
|
53
|
+
'--tai-color-primary-text',
|
|
54
|
+
'--tai-color-danger',
|
|
55
|
+
'--tai-color-danger-text',
|
|
56
|
+
'--tai-color-danger-hover',
|
|
57
|
+
'--tai-color-danger-surface',
|
|
58
|
+
'--tai-color-success',
|
|
59
|
+
'--tai-color-warning',
|
|
60
|
+
'--tai-space-1',
|
|
61
|
+
'--tai-space-2',
|
|
62
|
+
'--tai-space-3',
|
|
63
|
+
'--tai-space-4',
|
|
64
|
+
'--tai-space-5',
|
|
65
|
+
'--tai-space-6',
|
|
66
|
+
'--tai-space-8',
|
|
67
|
+
'--tai-radius-sm',
|
|
68
|
+
'--tai-radius-code',
|
|
69
|
+
'--tai-radius-md',
|
|
70
|
+
'--tai-radius-tile',
|
|
71
|
+
'--tai-radius-lg',
|
|
72
|
+
'--tai-radius-overlay',
|
|
73
|
+
'--tai-radius-full',
|
|
74
|
+
'--tai-font-sans',
|
|
75
|
+
'--tai-font-mono',
|
|
76
|
+
'--tai-text-display',
|
|
77
|
+
'--tai-text-xl',
|
|
78
|
+
'--tai-text-section',
|
|
79
|
+
'--tai-text-lg',
|
|
80
|
+
'--tai-text-md',
|
|
81
|
+
'--tai-text-sm',
|
|
82
|
+
'--tai-text-code',
|
|
83
|
+
'--tai-text-xs',
|
|
84
|
+
'--tai-control-height',
|
|
85
|
+
'--tai-control-height-coarse',
|
|
86
|
+
'--tai-motion-fast',
|
|
87
|
+
'--tai-motion-base',
|
|
88
|
+
'--tai-shadow-lift-color',
|
|
89
|
+
'--tai-shadow-overlay-color',
|
|
90
|
+
'--tai-shadow-lift',
|
|
91
|
+
'--tai-shadow-overlay',
|
|
92
|
+
'--tai-shadow-sm',
|
|
93
|
+
'--tai-shadow-md',
|
|
94
|
+
'--tai-z-sticky',
|
|
95
|
+
'--tai-z-dropdown',
|
|
96
|
+
'--tai-z-overlay',
|
|
97
|
+
'--tai-z-dialog',
|
|
98
|
+
'--tai-z-popover',
|
|
99
|
+
'--tai-z-tooltip',
|
|
100
|
+
] as const;
|
|
101
|
+
|
|
102
|
+
export type TokenName = (typeof TOKEN_NAMES)[number];
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ToolPicker` — a controlled single-select over the available tool names, built
|
|
3
|
+
* on the DS `Select` so features share one picker instead of each re-implementing
|
|
4
|
+
* a listbox (the same reason `SchemaForm` lives in the SDK). It is
|
|
5
|
+
* PRESENTATIONAL: the caller fetches the tool names (GET /api/tools) and owns the
|
|
6
|
+
* selected value; this component fetches nothing.
|
|
7
|
+
*
|
|
8
|
+
* Three optional extensions, each inert unless supplied; the preset create flow
|
|
9
|
+
* passes all three and the multi-tool picker the first two:
|
|
10
|
+
* - `excludeNames` removes names from the options (e.g. a preset cannot be
|
|
11
|
+
* another preset's base, so the preset create flow excludes existing preset
|
|
12
|
+
* names). The server stays the authority — a slipped-through name is rejected
|
|
13
|
+
* loudly there — this is only a UI convenience.
|
|
14
|
+
* - `tagsByTool` (from GET /api/tools/tags) turns on tag GROUPING + a tag FILTER:
|
|
15
|
+
* the options are grouped under their tag and a filter control narrows them to
|
|
16
|
+
* a chosen tag.
|
|
17
|
+
* - `agentToolNames` suffixes the LABEL of any option whose name is an agent run
|
|
18
|
+
* tool with " (agent)" (in grouped and flat renderings alike) — a purely visual
|
|
19
|
+
* honesty cue; the value stays the bare name and no option is excluded, since an
|
|
20
|
+
* agent run tool is a legal preset base for an authored agent.
|
|
21
|
+
*
|
|
22
|
+
* SAFETY: a tool name AND a tag are server-supplied, so every name/tag renders as
|
|
23
|
+
* TEXT through the DS `Select` (React escapes it) — never an HTML sink. Pinned by
|
|
24
|
+
* a test.
|
|
25
|
+
*/
|
|
26
|
+
import { useState } from 'react';
|
|
27
|
+
|
|
28
|
+
import { Field } from './field';
|
|
29
|
+
import { Select, type SelectGroup } from './select';
|
|
30
|
+
|
|
31
|
+
export interface ToolPickerProps {
|
|
32
|
+
readonly toolNames: readonly string[];
|
|
33
|
+
readonly value: string | null;
|
|
34
|
+
readonly onChange: (toolName: string) => void;
|
|
35
|
+
readonly disabled?: boolean;
|
|
36
|
+
readonly placeholder?: string;
|
|
37
|
+
readonly idPrefix?: string;
|
|
38
|
+
readonly label?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Accessible name for the tool listbox when `label` renders none and no
|
|
41
|
+
* enclosing `Field` names it. `label` wins where both are given: it names the
|
|
42
|
+
* control from visible text, and the `Select` drops a caller name it would
|
|
43
|
+
* otherwise override.
|
|
44
|
+
*/
|
|
45
|
+
readonly 'aria-label'?: string;
|
|
46
|
+
/** Names removed from the options (the server remains the authority). */
|
|
47
|
+
readonly excludeNames?: readonly string[];
|
|
48
|
+
/** Per-tool native tags; when present, options are grouped and a tag filter shows. */
|
|
49
|
+
readonly tagsByTool?: Readonly<Record<string, readonly string[]>>;
|
|
50
|
+
/** Tool names that are agent run tools; their option labels are suffixed " (agent)". */
|
|
51
|
+
readonly agentToolNames?: ReadonlySet<string>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const UNTAGGED = 'Untagged';
|
|
55
|
+
// Radix `Select.Item` forbids an empty-string value, so the "no filter" choice
|
|
56
|
+
// uses a sentinel rather than ''. A tool literally tagged this string would just
|
|
57
|
+
// never be filtered out — harmless for a UI convenience whose authority is the server.
|
|
58
|
+
const ALL_TAGS = '__all_tags__';
|
|
59
|
+
|
|
60
|
+
/** The group a tool sorts into: its alphabetically-first tag, else "Untagged". */
|
|
61
|
+
function groupFor(name: string, tagsByTool: Readonly<Record<string, readonly string[]>>): string {
|
|
62
|
+
const tags = [...(tagsByTool[name] ?? [])].sort((a, b) => a.localeCompare(b));
|
|
63
|
+
return tags[0] ?? UNTAGGED;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The option label: the bare name, suffixed " (agent)" for an agent run tool. */
|
|
67
|
+
function optionLabel(name: string, agentToolNames: ReadonlySet<string> | undefined): string {
|
|
68
|
+
return agentToolNames?.has(name) === true ? `${name} (agent)` : name;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Build the grouped option clusters (sorted group labels, "Untagged" last). */
|
|
72
|
+
function buildGroups(
|
|
73
|
+
names: readonly string[],
|
|
74
|
+
tagsByTool: Readonly<Record<string, readonly string[]>>,
|
|
75
|
+
agentToolNames: ReadonlySet<string> | undefined,
|
|
76
|
+
): SelectGroup[] {
|
|
77
|
+
const byGroup = new Map<string, string[]>();
|
|
78
|
+
for (const name of names) {
|
|
79
|
+
const group = groupFor(name, tagsByTool);
|
|
80
|
+
const bucket = byGroup.get(group) ?? [];
|
|
81
|
+
bucket.push(name);
|
|
82
|
+
byGroup.set(group, bucket);
|
|
83
|
+
}
|
|
84
|
+
return [...byGroup.entries()]
|
|
85
|
+
.sort(([a], [b]) => {
|
|
86
|
+
if (a === UNTAGGED) return 1;
|
|
87
|
+
if (b === UNTAGGED) return -1;
|
|
88
|
+
return a.localeCompare(b);
|
|
89
|
+
})
|
|
90
|
+
.map(([label, groupNames]) => ({
|
|
91
|
+
label,
|
|
92
|
+
options: groupNames.map((name) => ({
|
|
93
|
+
value: name,
|
|
94
|
+
label: optionLabel(name, agentToolNames),
|
|
95
|
+
})),
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function ToolPicker({
|
|
100
|
+
toolNames,
|
|
101
|
+
value,
|
|
102
|
+
onChange,
|
|
103
|
+
disabled,
|
|
104
|
+
placeholder = 'Select a tool…',
|
|
105
|
+
idPrefix = 'tool-picker',
|
|
106
|
+
label,
|
|
107
|
+
'aria-label': ariaLabel,
|
|
108
|
+
excludeNames,
|
|
109
|
+
tagsByTool,
|
|
110
|
+
agentToolNames,
|
|
111
|
+
}: ToolPickerProps) {
|
|
112
|
+
const [tagFilter, setTagFilter] = useState<string>(ALL_TAGS);
|
|
113
|
+
|
|
114
|
+
const excluded = new Set(excludeNames ?? []);
|
|
115
|
+
const available = toolNames.filter((name) => !excluded.has(name));
|
|
116
|
+
|
|
117
|
+
// Distinct tags across the available tools, sorted, feeding the filter control.
|
|
118
|
+
const allTags =
|
|
119
|
+
tagsByTool === undefined
|
|
120
|
+
? []
|
|
121
|
+
: [...new Set(available.flatMap((name) => tagsByTool[name] ?? []))].sort((a, b) =>
|
|
122
|
+
a.localeCompare(b),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const filtered =
|
|
126
|
+
tagsByTool !== undefined && tagFilter !== ALL_TAGS
|
|
127
|
+
? available.filter((name) => (tagsByTool[name] ?? []).includes(tagFilter))
|
|
128
|
+
: available;
|
|
129
|
+
|
|
130
|
+
const toolSelect =
|
|
131
|
+
tagsByTool !== undefined ? (
|
|
132
|
+
<Select
|
|
133
|
+
groups={buildGroups(filtered, tagsByTool, agentToolNames)}
|
|
134
|
+
value={value ?? ''}
|
|
135
|
+
onValueChange={onChange}
|
|
136
|
+
placeholder={placeholder}
|
|
137
|
+
aria-label={ariaLabel}
|
|
138
|
+
disabled={disabled}
|
|
139
|
+
/>
|
|
140
|
+
) : (
|
|
141
|
+
<Select
|
|
142
|
+
// Keep Radix controlled even when the caller's value is null: `''` matches no
|
|
143
|
+
// item (placeholder still shows) and avoids the uncontrolled→controlled warning
|
|
144
|
+
// a subsequent selection would otherwise trigger.
|
|
145
|
+
options={filtered.map((name) => ({
|
|
146
|
+
value: name,
|
|
147
|
+
label: optionLabel(name, agentToolNames),
|
|
148
|
+
}))}
|
|
149
|
+
value={value ?? ''}
|
|
150
|
+
onValueChange={onChange}
|
|
151
|
+
placeholder={placeholder}
|
|
152
|
+
aria-label={ariaLabel}
|
|
153
|
+
disabled={disabled}
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<div data-testid={idPrefix} className="tai-stack tai-stack-2">
|
|
159
|
+
{tagsByTool !== undefined && allTags.length > 0 ? (
|
|
160
|
+
<Field label="Filter by tag">
|
|
161
|
+
<Select
|
|
162
|
+
options={[
|
|
163
|
+
{ value: ALL_TAGS, label: 'All tags' },
|
|
164
|
+
...allTags.map((tag) => ({ value: tag, label: tag })),
|
|
165
|
+
]}
|
|
166
|
+
value={tagFilter}
|
|
167
|
+
onValueChange={setTagFilter}
|
|
168
|
+
disabled={disabled}
|
|
169
|
+
/>
|
|
170
|
+
</Field>
|
|
171
|
+
) : null}
|
|
172
|
+
{label !== undefined ? <Field label={label}>{toolSelect}</Field> : toolSelect}
|
|
173
|
+
</div>
|
|
174
|
+
);
|
|
175
|
+
}
|