@bluefly/openstandardagents 0.2.5-RC → 0.2.7
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/.github/ISSUE_TEMPLATE/bug_report.yml +63 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +40 -0
- package/.github/workflows/dependabot-comment.yml +34 -0
- package/.github/workflows/pr-comment.yml +33 -0
- package/.husky/pre-commit +5 -0
- package/.kiro/config.json +21 -0
- package/.kiro/settings/mcp.json +61 -0
- package/.kiro/specs/scripts-migration-api-first/design.md +883 -0
- package/.kiro/specs/scripts-migration-api-first/requirements.md +165 -0
- package/.kiro/specs/scripts-migration-api-first/tasks.md +539 -0
- package/.kiro/specs/{website-design-audit → website-brand-identity}/design.md +381 -0
- package/.kiro/specs/{website-design-audit → website-brand-identity}/requirements.md +88 -0
- package/.kiro/specs/website-brand-identity/tasks.md +981 -0
- package/CHANGELOG.md +23 -0
- package/README.md +12 -3
- package/bin/ossa-dev +42 -0
- package/bin/ossa-export +32 -0
- package/bin/ossa-generate +60 -0
- package/bin/ossa-health +40 -0
- package/bin/ossa-init +26 -0
- package/dist/repositories/schema.repository.d.ts.map +1 -1
- package/dist/repositories/schema.repository.js +15 -10
- package/dist/repositories/schema.repository.js.map +1 -1
- package/dist/services/github-sync/github-client.d.ts +14 -0
- package/dist/services/github-sync/github-client.d.ts.map +1 -0
- package/dist/services/github-sync/github-client.js +41 -0
- package/dist/services/github-sync/github-client.js.map +1 -0
- package/dist/services/github-sync/gitlab-client.d.ts +17 -0
- package/dist/services/github-sync/gitlab-client.d.ts.map +1 -0
- package/dist/services/github-sync/gitlab-client.js +42 -0
- package/dist/services/github-sync/gitlab-client.js.map +1 -0
- package/dist/services/github-sync/schemas.d.ts +46 -0
- package/dist/services/github-sync/schemas.d.ts.map +1 -0
- package/dist/services/github-sync/schemas.js +36 -0
- package/dist/services/github-sync/schemas.js.map +1 -0
- package/dist/services/github-sync/sync.service.d.ts +27 -0
- package/dist/services/github-sync/sync.service.d.ts.map +1 -0
- package/dist/services/github-sync/sync.service.js +99 -0
- package/dist/services/github-sync/sync.service.js.map +1 -0
- package/dist/services/runtime/claude/capability-mapper.d.ts +84 -0
- package/dist/services/runtime/claude/capability-mapper.d.ts.map +1 -0
- package/dist/services/runtime/claude/capability-mapper.js +245 -0
- package/dist/services/runtime/claude/capability-mapper.js.map +1 -0
- package/dist/services/runtime/claude/claude-adapter.d.ts +80 -0
- package/dist/services/runtime/claude/claude-adapter.d.ts.map +1 -0
- package/dist/services/runtime/claude/claude-adapter.js +287 -0
- package/dist/services/runtime/claude/claude-adapter.js.map +1 -0
- package/dist/services/runtime/claude/manifest-parser.d.ts +77 -0
- package/dist/services/runtime/claude/manifest-parser.d.ts.map +1 -0
- package/dist/services/runtime/claude/manifest-parser.js +169 -0
- package/dist/services/runtime/claude/manifest-parser.js.map +1 -0
- package/dist/services/runtime/claude/types.d.ts +115 -0
- package/dist/services/runtime/claude/types.d.ts.map +1 -0
- package/dist/services/runtime/claude/types.js +6 -0
- package/dist/services/runtime/claude/types.js.map +1 -0
- package/dist/services/validation.service.d.ts.map +1 -1
- package/dist/services/validation.service.js +12 -1
- package/dist/services/validation.service.js.map +1 -1
- package/dist/spec/v0.2.4/ossa-0.2.4.schema.json +85 -208
- package/dist/spec/v0.2.6/CHANGELOG.md +401 -0
- package/dist/spec/v0.2.6/README.md +72 -0
- package/dist/spec/v0.2.6/migrations/v0.2.3-to-v0.2.4.md +599 -0
- package/dist/spec/v0.2.6/migrations/v0.2.5-RC-to-v0.2.6.md +65 -0
- package/dist/spec/v0.2.6/ossa-0.2.6.schema.json +1786 -0
- package/dist/spec/v0.2.6/ossa-0.2.6.yaml +581 -0
- package/dist/spec/v0.2.6-dev/CHANGELOG.md +164 -0
- package/dist/spec/v0.2.6-dev/README.md +75 -0
- package/dist/spec/v0.2.6-dev/migrations/v0.2.2-to-v0.2.3.md +343 -0
- package/dist/spec/v0.2.6-dev/migrations/v0.2.3-to-v0.2.4.md +599 -0
- package/dist/spec/{v0.2.4/ossa-0.2.4-dev.schema.json → v0.2.6-dev/ossa-0.2.5.schema.json} +9 -9
- package/dist/spec/v0.2.6-dev/ossa-0.2.5.yaml +581 -0
- package/{spec/v0.2.4/ossa-0.2.4-dev.schema.json → dist/spec/v0.2.6-dev/ossa-0.2.6-dev.schema.json} +9 -9
- package/dist/spec/v0.2.6-dev/ossa-0.2.6-dev.yaml +448 -0
- package/dist/spec/v0.2.7/core/agentgraph.md +324 -0
- package/dist/spec/v0.2.7/resources/agentgraph.yaml +135 -0
- package/docs/brand-guide/01-brand-overview.md +37 -0
- package/docs/brand-guide/02-logo-usage.md +43 -0
- package/docs/brand-guide/03-color-palette.md +70 -0
- package/docs/brand-guide/04-typography.md +82 -0
- package/docs/brand-guide/05-voice-and-tone.md +108 -0
- package/docs/brand-guide/06-visual-elements.md +137 -0
- package/docs/brand-guide/07-application-examples.md +153 -0
- package/docs/brand-guide/OssaLogo/OssA_Logo.svg +21 -0
- package/docs/brand-guide/OssaLogo/brand.af +0 -0
- package/docs/brand-guide/README.md +107 -0
- package/docs/comparison.md +315 -0
- package/docs/operations/automation-roadmap.md +245 -0
- package/docs/operations/github-sync-strategy.md +357 -0
- package/examples/anthropic/claude-assistant.ossa.json +5 -4
- package/examples/autogen/multi-agent.ossa.json +6 -4
- package/examples/crewai/research-team.ossa.json +14 -5
- package/examples/cursor/code-review-agent.ossa.json +21 -6
- package/examples/langchain/chain-agent.ossa.json +21 -5
- package/examples/langflow/workflow-agent.ossa.json +2 -3
- package/examples/langgraph/state-machine-agent.ossa.json +2 -3
- package/examples/llamaindex/rag-agent.ossa.json +2 -3
- package/examples/openai/multi-tool-agent.ossa.json +32 -9
- package/examples/openai/swarm-agent.ossa.json +18 -5
- package/examples/vercel/edge-agent.ossa.json +5 -4
- package/openapi/github-sync.yaml +115 -0
- package/package.json +25 -4
- package/scripts/README.md +103 -0
- package/scripts/auto-rebase-mrs.ts +106 -0
- package/scripts/batch-dependabot.sh +57 -0
- package/scripts/configure-gitlab-branch-protection.ts +95 -0
- package/scripts/create-issue-helper.ts +238 -0
- package/scripts/create-milestone-issue.ts +73 -0
- package/scripts/fix-schema-formats.js +82 -0
- package/scripts/generate-agents-catalog.ts +77 -0
- package/scripts/generate-api-docs.ts +218 -0
- package/scripts/generate-cli-docs.ts +410 -0
- package/scripts/generate-config-docs.ts +109 -0
- package/scripts/generate-errors-docs.ts +76 -0
- package/scripts/generate-examples-docs.ts +99 -0
- package/scripts/generate-schema-docs.ts +296 -0
- package/scripts/generate-types-docs.ts +48 -0
- package/scripts/lowercase-docs.ts +43 -0
- package/scripts/manage-milestone-mrs.ts +279 -0
- package/scripts/rebase-all-mrs.sh +75 -0
- package/scripts/sync-github-pr.sh +48 -0
- package/scripts/sync-version.js +40 -0
- package/scripts/sync-wiki.sh +50 -0
- package/scripts/validate-all.js +127 -0
- package/spec/v0.2.4/ossa-0.2.4.schema.json +85 -208
- package/spec/v0.2.6/CHANGELOG.md +401 -0
- package/spec/v0.2.6/README.md +72 -0
- package/spec/v0.2.6/migrations/v0.2.3-to-v0.2.4.md +599 -0
- package/spec/v0.2.6/migrations/v0.2.5-RC-to-v0.2.6.md +65 -0
- package/spec/v0.2.6/ossa-0.2.6.schema.json +1786 -0
- package/spec/v0.2.6/ossa-0.2.6.yaml +581 -0
- package/spec/v0.2.6-dev/CHANGELOG.md +164 -0
- package/spec/v0.2.6-dev/README.md +75 -0
- package/spec/v0.2.6-dev/migrations/v0.2.2-to-v0.2.3.md +343 -0
- package/spec/v0.2.6-dev/migrations/v0.2.3-to-v0.2.4.md +599 -0
- package/spec/v0.2.6-dev/ossa-0.2.5.schema.json +1696 -0
- package/spec/v0.2.6-dev/ossa-0.2.5.yaml +581 -0
- package/spec/v0.2.6-dev/ossa-0.2.6-dev.schema.json +1696 -0
- package/spec/v0.2.6-dev/ossa-0.2.6-dev.yaml +448 -0
- package/spec/v0.2.7/core/agentgraph.md +324 -0
- package/spec/v0.2.7/resources/agentgraph.yaml +135 -0
- package/website/DESIGN_SYSTEM_IMPLEMENTATION.md +445 -0
- package/website/app/about/page.tsx +53 -44
- package/website/app/ecosystem/page.tsx +146 -111
- package/website/app/globals.scss +256 -21
- package/website/app/page.tsx +394 -182
- package/website/app/page.tsx.bak +679 -0
- package/website/app/page.tsx.bak2 +649 -0
- package/website/app/schema/page.tsx +3 -3
- package/website/app/specification/page.tsx +1 -1
- package/website/components/layout/Header.tsx +27 -23
- package/website/components/ui/Badge.tsx +82 -0
- package/website/components/ui/Button.tsx +116 -0
- package/website/components/ui/Card.tsx +167 -0
- package/website/components/ui/Checkbox.tsx +141 -0
- package/website/components/ui/Input.tsx +169 -0
- package/website/components/ui/Radio.tsx +141 -0
- package/website/components/ui/Select.tsx +182 -0
- package/website/components/ui/Tag.tsx +158 -0
- package/website/components/ui/Textarea.tsx +195 -0
- package/website/components/ui/index.ts +11 -0
- package/website/content/docs/{00-HOME.md → 00-home.md} +1 -1
- package/website/content/docs/agents/catalog.md +28 -0
- package/website/content/docs/{AIFlow-Framework-Integration-with-OSSA.md → aiflow-framework-integration-with-ossa.md} +2 -2
- package/website/content/docs/api-reference/index.md +38 -0
- package/website/content/docs/api-reference/ossa-core-api.md +634 -0
- package/website/content/docs/api-reference/ossa-registry-api.md +515 -0
- package/website/content/docs/api-reference/unified-agent-gateway.md +599 -0
- package/website/content/docs/cli-reference/index.md +111 -0
- package/website/content/docs/cli-reference/ossa-agents.md +70 -0
- package/website/content/docs/cli-reference/ossa-export.md +56 -0
- package/website/content/docs/cli-reference/ossa-generate.md +66 -0
- package/website/content/docs/cli-reference/ossa-gitlab-agent.md +57 -0
- package/website/content/docs/cli-reference/ossa-import.md +56 -0
- package/website/content/docs/cli-reference/ossa-init.md +57 -0
- package/website/content/docs/cli-reference/ossa-migrate.md +62 -0
- package/website/content/docs/cli-reference/ossa-run.md +66 -0
- package/website/content/docs/cli-reference/ossa-schema.md +57 -0
- package/website/content/docs/cli-reference/ossa-setup.md +57 -0
- package/website/content/docs/cli-reference/ossa-validate.md +66 -0
- package/website/content/docs/configuration/index.md +97 -0
- package/website/content/docs/deployment/github-mirroring.md +924 -0
- package/website/content/docs/documentation.md +100 -0
- package/website/content/docs/ecosystem/framework-support.md +551 -9
- package/website/content/docs/errors/index.md +10 -0
- package/website/content/docs/examples/{AIFlow-Framework-Integration-with-OSSA.md → aiflow-framework-integration-with-ossa.md} +2 -2
- package/website/content/docs/examples/catalog.md +300 -0
- package/website/content/docs/for-audiences/{Students-Researchers.md → students-researchers.md} +1 -1
- package/website/content/docs/getting-started/{Installation.md → installation.md} +1 -1
- package/website/content/docs/getting-started.md +1 -1
- package/website/content/docs/integrations/aiflow.md +2 -2
- package/website/content/docs/migration-guides/anthropic-mcp-to-ossa.md +5 -5
- package/website/content/docs/migration-guides/crewai-to-ossa.md +3 -3
- package/website/content/docs/migration-guides/drupal-eca-to-ossa.md +7 -7
- package/website/content/docs/migration-guides/langchain-to-ossa.md +4 -4
- package/website/content/docs/openapi-extensions/index.md +1 -1
- package/website/content/docs/ossa-compliant-badge.md +1 -1
- package/website/content/docs/pre-release/index.md +5 -5
- package/website/content/docs/releases/v0.2.6.md +99 -0
- package/website/content/docs/schema-reference/agent-capabilities.md +50 -0
- package/website/content/docs/schema-reference/agent-id.md +52 -0
- package/website/content/docs/schema-reference/agent-name.md +50 -0
- package/website/content/docs/schema-reference/agent-role.md +54 -0
- package/website/content/docs/schema-reference/agent-version.md +50 -0
- package/website/content/docs/schema-reference/index.md +26 -157
- package/website/content/docs/types-reference/index.md +105 -0
- package/website/content/docs/versioning.md +3 -3
- package/website/dev.sh +53 -0
- package/website/docker-compose.dev.yml +36 -0
- package/website/lib/version.ts +1 -1
- package/website/lib/versions.json +45 -20
- package/website/package.json +1 -1
- package/website/styles/_spacing.scss +453 -0
- package/website/styles/_tokens.scss +245 -0
- package/website/styles/_typography.scss +361 -0
- package/website/styles/_variables.scss +270 -19
- package/website/tailwind.config.ts +113 -79
- package/.kiro/specs/agent-buildkit-templates/design.md +0 -495
- package/.kiro/specs/agent-buildkit-templates/requirements.md +0 -165
- package/.kiro/specs/kiro-ide-supercharger/README.md +0 -202
- package/.kiro/specs/kiro-ide-supercharger/design.md +0 -1005
- package/.kiro/specs/kiro-ide-supercharger/requirements.md +0 -141
- package/.kiro/specs/kiro-ide-supercharger/tasks.md +0 -507
- package/docs/issue-19-completion-summary.md +0 -648
- package/docs/issue-19-validation.md +0 -351
- package/website/content/docs/Examples.md +0 -71
- package/website/content/docs/OpenAPI-Extensions.md +0 -934
- package/website/content/docs/core-concepts/Project-Structure.md +0 -348
- package/website/content/docs/examples/Migration-Guides.md +0 -214
- package/website/content/docs/for-audiences/Architects.md +0 -224
- package/website/content/docs/for-audiences/Developers.md +0 -220
- package/website/content/docs/for-audiences/Enterprises.md +0 -256
- package/website/content/docs/getting-started/5-Minute-Overview.md +0 -85
- package/website/content/docs/getting-started/First-Agent.md +0 -196
- package/website/content/docs/getting-started/Hello-World.md +0 -184
- package/website/content/docs/migration-guides/00-INDEX.md +0 -76
- package/website/content/docs/migration-guides/README.md +0 -133
- /package/dist/spec/v0.2.4/{ossa-0.2.4-dev.yaml → ossa-0.2.4.yaml} +0 -0
- /package/spec/v0.2.4/{ossa-0.2.4-dev.yaml → ossa-0.2.4.yaml} +0 -0
|
@@ -12,13 +12,13 @@ function getStableVersion(): string {
|
|
|
12
12
|
const versionsPath = path.join(process.cwd(), 'lib', 'versions.json');
|
|
13
13
|
if (fs.existsSync(versionsPath)) {
|
|
14
14
|
const versions = JSON.parse(fs.readFileSync(versionsPath, 'utf8'));
|
|
15
|
-
return versions.stable || '0.2.
|
|
15
|
+
return versions.stable || '0.2.6';
|
|
16
16
|
}
|
|
17
17
|
} catch (error) {
|
|
18
18
|
console.error('Error reading versions.json:', error);
|
|
19
19
|
}
|
|
20
|
-
// Fallback to 0.2.
|
|
21
|
-
return '0.2.
|
|
20
|
+
// Fallback to 0.2.6 if versions.json not available
|
|
21
|
+
return '0.2.6';
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// Try to load schema dynamically - fallback to stable version
|
|
@@ -225,7 +225,7 @@ spec:
|
|
|
225
225
|
|
|
226
226
|
<div className="bg-white border-2 border-gray-200 rounded-xl p-6 shadow-md">
|
|
227
227
|
<div className="flex items-center justify-between mb-2">
|
|
228
|
-
<h3 className="text-xl font-semibold text-gray-900">v0.2.
|
|
228
|
+
<h3 className="text-xl font-semibold text-gray-900">v0.2.6</h3>
|
|
229
229
|
<span className="px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm font-medium">
|
|
230
230
|
Previous
|
|
231
231
|
</span>
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import Link from 'next/link';
|
|
4
|
+
import { usePathname } from 'next/navigation';
|
|
4
5
|
import { useState } from 'react';
|
|
5
6
|
|
|
6
7
|
export function Header() {
|
|
7
8
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
9
|
+
const pathname = usePathname();
|
|
10
|
+
|
|
11
|
+
const isActive = (path: string) => pathname === path || pathname?.startsWith(path + '/');
|
|
8
12
|
|
|
9
13
|
return (
|
|
10
14
|
<header className="bg-white border-b border-gray-300 sticky top-0 z-50">
|
|
11
15
|
<nav className="container mx-auto max-w-6xl px-4">
|
|
12
16
|
<div className="flex items-center justify-between h-16">
|
|
13
|
-
<Link href="/" className="flex items-center space-x-
|
|
17
|
+
<Link href="/" className="flex items-center space-x-2 group">
|
|
14
18
|
<img
|
|
15
19
|
src="/assets/brand/ossa-logo.svg"
|
|
16
20
|
alt="OSSA Logo"
|
|
@@ -23,25 +27,25 @@ export function Header() {
|
|
|
23
27
|
|
|
24
28
|
{/* Desktop Navigation */}
|
|
25
29
|
<div className="hidden md:flex items-center space-x-3 lg:space-x-6 text-sm lg:text-base">
|
|
26
|
-
<Link href="/about" className=
|
|
30
|
+
<Link href="/about" className={`px-3 py-2 rounded-lg transition-all font-medium whitespace-nowrap ${isActive('/about') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}>
|
|
27
31
|
About
|
|
28
32
|
</Link>
|
|
29
|
-
<Link href="/specification" className=
|
|
33
|
+
<Link href="/specification" className={`px-3 py-2 rounded-lg transition-all font-medium whitespace-nowrap ${isActive('/specification') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}>
|
|
30
34
|
Specification
|
|
31
35
|
</Link>
|
|
32
|
-
<Link href="/schema" className=
|
|
36
|
+
<Link href="/schema" className={`px-3 py-2 rounded-lg transition-all font-medium whitespace-nowrap ${isActive('/schema') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}>
|
|
33
37
|
Schema
|
|
34
38
|
</Link>
|
|
35
|
-
<Link href="/docs" className=
|
|
39
|
+
<Link href="/docs" className={`px-3 py-2 rounded-lg transition-all font-medium whitespace-nowrap ${isActive('/docs') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}>
|
|
36
40
|
Docs
|
|
37
41
|
</Link>
|
|
38
|
-
<Link href="/blog" className=
|
|
42
|
+
<Link href="/blog" className={`px-3 py-2 rounded-lg transition-all font-medium whitespace-nowrap ${isActive('/blog') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}>
|
|
39
43
|
Blog
|
|
40
44
|
</Link>
|
|
41
|
-
<Link href="/playground" className=
|
|
45
|
+
<Link href="/playground" className={`px-3 py-2 rounded-lg transition-all font-medium whitespace-nowrap ${isActive('/playground') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}>
|
|
42
46
|
Playground
|
|
43
47
|
</Link>
|
|
44
|
-
<Link href="/examples" className=
|
|
48
|
+
<Link href="/examples" className={`px-3 py-2 rounded-lg transition-all font-medium whitespace-nowrap ${isActive('/examples') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}>
|
|
45
49
|
Examples
|
|
46
50
|
</Link>
|
|
47
51
|
<a
|
|
@@ -91,58 +95,59 @@ export function Header() {
|
|
|
91
95
|
</div>
|
|
92
96
|
|
|
93
97
|
{/* Mobile Navigation */}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
<div
|
|
99
|
+
id="mobile-menu"
|
|
100
|
+
className={`md:hidden overflow-hidden transition-all duration-300 ease-in-out ${
|
|
101
|
+
mobileMenuOpen ? 'max-h-96 opacity-100 py-4 border-t border-gray-300' : 'max-h-0 opacity-0'
|
|
102
|
+
}`}
|
|
103
|
+
role="navigation"
|
|
104
|
+
aria-label="Mobile navigation"
|
|
105
|
+
>
|
|
101
106
|
<Link
|
|
102
107
|
href="/about"
|
|
103
|
-
className=
|
|
108
|
+
className={`block px-3 py-2 rounded-lg transition-all font-medium ${isActive('/about') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}
|
|
104
109
|
onClick={() => setMobileMenuOpen(false)}
|
|
105
110
|
>
|
|
106
111
|
About
|
|
107
112
|
</Link>
|
|
108
113
|
<Link
|
|
109
114
|
href="/specification"
|
|
110
|
-
className=
|
|
115
|
+
className={`block px-3 py-2 rounded-lg transition-all font-medium ${isActive('/specification') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}
|
|
111
116
|
onClick={() => setMobileMenuOpen(false)}
|
|
112
117
|
>
|
|
113
118
|
Specification
|
|
114
119
|
</Link>
|
|
115
120
|
<Link
|
|
116
121
|
href="/schema"
|
|
117
|
-
className=
|
|
122
|
+
className={`block px-3 py-2 rounded-lg transition-all font-medium ${isActive('/schema') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}
|
|
118
123
|
onClick={() => setMobileMenuOpen(false)}
|
|
119
124
|
>
|
|
120
125
|
Schema
|
|
121
126
|
</Link>
|
|
122
127
|
<Link
|
|
123
128
|
href="/docs"
|
|
124
|
-
className=
|
|
129
|
+
className={`block px-3 py-2 rounded-lg transition-all font-medium ${isActive('/docs') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}
|
|
125
130
|
onClick={() => setMobileMenuOpen(false)}
|
|
126
131
|
>
|
|
127
132
|
Docs
|
|
128
133
|
</Link>
|
|
129
134
|
<Link
|
|
130
135
|
href="/blog"
|
|
131
|
-
className=
|
|
136
|
+
className={`block px-3 py-2 rounded-lg transition-all font-medium ${isActive('/blog') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}
|
|
132
137
|
onClick={() => setMobileMenuOpen(false)}
|
|
133
138
|
>
|
|
134
139
|
Blog
|
|
135
140
|
</Link>
|
|
136
141
|
<Link
|
|
137
142
|
href="/playground"
|
|
138
|
-
className=
|
|
143
|
+
className={`block px-3 py-2 rounded-lg transition-all font-medium ${isActive('/playground') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}
|
|
139
144
|
onClick={() => setMobileMenuOpen(false)}
|
|
140
145
|
>
|
|
141
146
|
Playground
|
|
142
147
|
</Link>
|
|
143
148
|
<Link
|
|
144
149
|
href="/examples"
|
|
145
|
-
className=
|
|
150
|
+
className={`block px-3 py-2 rounded-lg transition-all font-medium ${isActive('/examples') ? 'text-primary bg-primary/10' : 'text-gray-600 hover:text-primary hover:bg-primary/5'}`}
|
|
146
151
|
onClick={() => setMobileMenuOpen(false)}
|
|
147
152
|
>
|
|
148
153
|
Examples
|
|
@@ -160,7 +165,6 @@ export function Header() {
|
|
|
160
165
|
</svg>
|
|
161
166
|
</a>
|
|
162
167
|
</div>
|
|
163
|
-
)}
|
|
164
168
|
</nav>
|
|
165
169
|
</header>
|
|
166
170
|
);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type BadgeVariant = 'default' | 'success' | 'warning' | 'error' | 'info' | 'primary' | 'secondary';
|
|
4
|
+
type BadgeSize = 'sm' | 'md' | 'lg';
|
|
5
|
+
|
|
6
|
+
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
7
|
+
/** Badge content */
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
/** Visual variant */
|
|
10
|
+
variant?: BadgeVariant;
|
|
11
|
+
/** Size variant */
|
|
12
|
+
size?: BadgeSize;
|
|
13
|
+
/** Icon to display before text */
|
|
14
|
+
icon?: React.ReactNode;
|
|
15
|
+
/** Dot indicator instead of full background */
|
|
16
|
+
dot?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const variantClasses: Record<BadgeVariant, string> = {
|
|
20
|
+
default: 'bg-gray-100 text-gray-800 border border-gray-300',
|
|
21
|
+
success: 'bg-success-100 text-success-800 border border-success-300',
|
|
22
|
+
warning: 'bg-warning-100 text-warning-800 border border-warning-300',
|
|
23
|
+
error: 'bg-error-100 text-error-800 border border-error-300',
|
|
24
|
+
info: 'bg-info-100 text-info-800 border border-info-300',
|
|
25
|
+
primary: 'bg-primary-100 text-primary-800 border border-primary-300',
|
|
26
|
+
secondary: 'bg-secondary-100 text-secondary-800 border border-secondary-300',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const sizeClasses: Record<BadgeSize, string> = {
|
|
30
|
+
sm: 'px-2 py-0.5 text-xs',
|
|
31
|
+
md: 'px-3 py-1 text-sm',
|
|
32
|
+
lg: 'px-4 py-1.5 text-base',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const dotVariantClasses: Record<BadgeVariant, string> = {
|
|
36
|
+
default: 'bg-gray-500',
|
|
37
|
+
success: 'bg-success-500',
|
|
38
|
+
warning: 'bg-warning-500',
|
|
39
|
+
error: 'bg-error-500',
|
|
40
|
+
info: 'bg-info-500',
|
|
41
|
+
primary: 'bg-primary-500',
|
|
42
|
+
secondary: 'bg-secondary-500',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
|
|
46
|
+
(
|
|
47
|
+
{
|
|
48
|
+
className = '',
|
|
49
|
+
variant = 'default',
|
|
50
|
+
size = 'md',
|
|
51
|
+
children,
|
|
52
|
+
icon,
|
|
53
|
+
dot = false,
|
|
54
|
+
...props
|
|
55
|
+
},
|
|
56
|
+
ref
|
|
57
|
+
) => {
|
|
58
|
+
const classes = [
|
|
59
|
+
'inline-flex items-center justify-center rounded-full font-semibold',
|
|
60
|
+
variantClasses[variant],
|
|
61
|
+
sizeClasses[size],
|
|
62
|
+
className,
|
|
63
|
+
]
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
.join(' ');
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<span ref={ref} className={classes} {...props}>
|
|
69
|
+
{dot && (
|
|
70
|
+
<span
|
|
71
|
+
className={`w-2 h-2 rounded-full mr-1.5 ${dotVariantClasses[variant]}`}
|
|
72
|
+
aria-hidden="true"
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
{icon && <span className="mr-1">{icon}</span>}
|
|
76
|
+
{children}
|
|
77
|
+
</span>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
Badge.displayName = 'Badge';
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'success';
|
|
4
|
+
type ButtonSize = 'sm' | 'md' | 'lg';
|
|
5
|
+
|
|
6
|
+
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
|
+
/** Button content */
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
/** Visual variant */
|
|
10
|
+
variant?: ButtonVariant;
|
|
11
|
+
/** Size variant */
|
|
12
|
+
size?: ButtonSize;
|
|
13
|
+
/** Full width button */
|
|
14
|
+
fullWidth?: boolean;
|
|
15
|
+
/** Loading state */
|
|
16
|
+
loading?: boolean;
|
|
17
|
+
/** Icon to display before text */
|
|
18
|
+
iconLeft?: React.ReactNode;
|
|
19
|
+
/** Icon to display after text */
|
|
20
|
+
iconRight?: React.ReactNode;
|
|
21
|
+
/** Accessible label for screen readers */
|
|
22
|
+
ariaLabel?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const variantClasses: Record<ButtonVariant, string> = {
|
|
26
|
+
primary:
|
|
27
|
+
'bg-gradient-to-r from-secondary via-primary to-accent text-white hover:shadow-lg hover:scale-105 focus:ring-primary/30',
|
|
28
|
+
secondary:
|
|
29
|
+
'bg-secondary text-white hover:bg-secondary/90 hover:shadow-md focus:ring-secondary/30',
|
|
30
|
+
outline:
|
|
31
|
+
'border-2 border-primary text-primary bg-transparent hover:bg-primary hover:text-white focus:ring-primary/30',
|
|
32
|
+
ghost:
|
|
33
|
+
'text-primary bg-transparent hover:bg-primary/10 focus:ring-primary/20',
|
|
34
|
+
danger:
|
|
35
|
+
'bg-error text-white hover:bg-error-600 hover:shadow-md focus:ring-error/30',
|
|
36
|
+
success:
|
|
37
|
+
'bg-success text-white hover:bg-success-600 hover:shadow-md focus:ring-success/30',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const sizeClasses: Record<ButtonSize, string> = {
|
|
41
|
+
sm: 'px-4 py-2 text-sm min-h-[36px]',
|
|
42
|
+
md: 'px-6 py-3 text-base min-h-[44px]',
|
|
43
|
+
lg: 'px-8 py-4 text-lg min-h-[52px]',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
47
|
+
(
|
|
48
|
+
{
|
|
49
|
+
className = '',
|
|
50
|
+
variant = 'primary',
|
|
51
|
+
size = 'md',
|
|
52
|
+
fullWidth = false,
|
|
53
|
+
children,
|
|
54
|
+
loading = false,
|
|
55
|
+
iconLeft,
|
|
56
|
+
iconRight,
|
|
57
|
+
disabled,
|
|
58
|
+
ariaLabel,
|
|
59
|
+
...props
|
|
60
|
+
},
|
|
61
|
+
ref
|
|
62
|
+
) => {
|
|
63
|
+
const baseClasses =
|
|
64
|
+
'inline-flex items-center justify-center rounded-lg font-semibold transition-all duration-200 focus:outline-none focus:ring-4 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed';
|
|
65
|
+
|
|
66
|
+
const classes = [
|
|
67
|
+
baseClasses,
|
|
68
|
+
variantClasses[variant],
|
|
69
|
+
sizeClasses[size],
|
|
70
|
+
fullWidth ? 'w-full' : 'w-auto',
|
|
71
|
+
className,
|
|
72
|
+
]
|
|
73
|
+
.filter(Boolean)
|
|
74
|
+
.join(' ');
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<button
|
|
78
|
+
ref={ref}
|
|
79
|
+
className={classes}
|
|
80
|
+
disabled={disabled || loading}
|
|
81
|
+
aria-label={ariaLabel}
|
|
82
|
+
aria-busy={loading}
|
|
83
|
+
{...props}
|
|
84
|
+
>
|
|
85
|
+
{loading && (
|
|
86
|
+
<svg
|
|
87
|
+
className="animate-spin -ml-1 mr-3 h-5 w-5"
|
|
88
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
89
|
+
fill="none"
|
|
90
|
+
viewBox="0 0 24 24"
|
|
91
|
+
aria-hidden="true"
|
|
92
|
+
>
|
|
93
|
+
<circle
|
|
94
|
+
className="opacity-25"
|
|
95
|
+
cx="12"
|
|
96
|
+
cy="12"
|
|
97
|
+
r="10"
|
|
98
|
+
stroke="currentColor"
|
|
99
|
+
strokeWidth="4"
|
|
100
|
+
/>
|
|
101
|
+
<path
|
|
102
|
+
className="opacity-75"
|
|
103
|
+
fill="currentColor"
|
|
104
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
105
|
+
/>
|
|
106
|
+
</svg>
|
|
107
|
+
)}
|
|
108
|
+
{!loading && iconLeft && <span className="mr-2">{iconLeft}</span>}
|
|
109
|
+
{children}
|
|
110
|
+
{!loading && iconRight && <span className="ml-2">{iconRight}</span>}
|
|
111
|
+
</button>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
Button.displayName = 'Button';
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type CardVariant = 'default' | 'featured' | 'interactive' | 'ghost';
|
|
4
|
+
type CardPadding = 'sm' | 'md' | 'lg';
|
|
5
|
+
type CardElevation = 0 | 1 | 2 | 3;
|
|
6
|
+
|
|
7
|
+
export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
/** Card content */
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
/** Visual variant */
|
|
11
|
+
variant?: CardVariant;
|
|
12
|
+
/** Padding size */
|
|
13
|
+
padding?: CardPadding;
|
|
14
|
+
/** Shadow elevation level */
|
|
15
|
+
elevation?: CardElevation;
|
|
16
|
+
/** Enable hover effects */
|
|
17
|
+
hover?: boolean;
|
|
18
|
+
/** Make card clickable */
|
|
19
|
+
onClick?: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const variantClasses: Record<CardVariant, string> = {
|
|
23
|
+
default: 'bg-white border border-gray-200 rounded-xl',
|
|
24
|
+
featured:
|
|
25
|
+
'bg-gradient-to-br from-blue-50 to-indigo-50 border-2 border-primary/20 rounded-xl',
|
|
26
|
+
interactive:
|
|
27
|
+
'bg-white border-2 border-gray-200 rounded-xl cursor-pointer hover:border-primary',
|
|
28
|
+
ghost: 'bg-transparent border-none',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const paddingClasses: Record<CardPadding, string> = {
|
|
32
|
+
sm: 'p-4',
|
|
33
|
+
md: 'p-6',
|
|
34
|
+
lg: 'p-8',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const elevationClasses: Record<CardElevation, string> = {
|
|
38
|
+
0: 'shadow-none',
|
|
39
|
+
1: 'shadow-sm',
|
|
40
|
+
2: 'shadow-md',
|
|
41
|
+
3: 'shadow-lg',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const hoverClasses = 'hover:shadow-xl hover:-translate-y-1 transition-all duration-300';
|
|
45
|
+
|
|
46
|
+
export const Card = React.forwardRef<HTMLDivElement, CardProps>(
|
|
47
|
+
(
|
|
48
|
+
{
|
|
49
|
+
className = '',
|
|
50
|
+
variant = 'default',
|
|
51
|
+
padding = 'md',
|
|
52
|
+
elevation = 1,
|
|
53
|
+
hover = false,
|
|
54
|
+
children,
|
|
55
|
+
onClick,
|
|
56
|
+
...props
|
|
57
|
+
},
|
|
58
|
+
ref
|
|
59
|
+
) => {
|
|
60
|
+
const classes = [
|
|
61
|
+
variantClasses[variant],
|
|
62
|
+
paddingClasses[padding],
|
|
63
|
+
elevationClasses[elevation],
|
|
64
|
+
hover || onClick ? hoverClasses : '',
|
|
65
|
+
onClick ? 'cursor-pointer' : '',
|
|
66
|
+
className,
|
|
67
|
+
]
|
|
68
|
+
.filter(Boolean)
|
|
69
|
+
.join(' ');
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div
|
|
73
|
+
ref={ref}
|
|
74
|
+
className={classes}
|
|
75
|
+
onClick={onClick}
|
|
76
|
+
role={onClick ? 'button' : undefined}
|
|
77
|
+
tabIndex={onClick ? 0 : undefined}
|
|
78
|
+
onKeyDown={
|
|
79
|
+
onClick
|
|
80
|
+
? (e) => {
|
|
81
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
onClick();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
: undefined
|
|
87
|
+
}
|
|
88
|
+
{...props}
|
|
89
|
+
>
|
|
90
|
+
{children}
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
Card.displayName = 'Card';
|
|
97
|
+
|
|
98
|
+
// Card sub-components for better composition
|
|
99
|
+
export const CardHeader: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
|
|
100
|
+
className = '',
|
|
101
|
+
children,
|
|
102
|
+
...props
|
|
103
|
+
}) => {
|
|
104
|
+
return (
|
|
105
|
+
<div className={`mb-4 ${className}`} {...props}>
|
|
106
|
+
{children}
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
CardHeader.displayName = 'CardHeader';
|
|
112
|
+
|
|
113
|
+
export const CardTitle: React.FC<React.HTMLAttributes<HTMLHeadingElement>> = ({
|
|
114
|
+
className = '',
|
|
115
|
+
children,
|
|
116
|
+
...props
|
|
117
|
+
}) => {
|
|
118
|
+
return (
|
|
119
|
+
<h3 className={`text-2xl font-semibold text-gray-900 ${className}`} {...props}>
|
|
120
|
+
{children}
|
|
121
|
+
</h3>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
CardTitle.displayName = 'CardTitle';
|
|
126
|
+
|
|
127
|
+
export const CardDescription: React.FC<React.HTMLAttributes<HTMLParagraphElement>> = ({
|
|
128
|
+
className = '',
|
|
129
|
+
children,
|
|
130
|
+
...props
|
|
131
|
+
}) => {
|
|
132
|
+
return (
|
|
133
|
+
<p className={`text-gray-600 ${className}`} {...props}>
|
|
134
|
+
{children}
|
|
135
|
+
</p>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
CardDescription.displayName = 'CardDescription';
|
|
140
|
+
|
|
141
|
+
export const CardContent: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
|
|
142
|
+
className = '',
|
|
143
|
+
children,
|
|
144
|
+
...props
|
|
145
|
+
}) => {
|
|
146
|
+
return (
|
|
147
|
+
<div className={className} {...props}>
|
|
148
|
+
{children}
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
CardContent.displayName = 'CardContent';
|
|
154
|
+
|
|
155
|
+
export const CardFooter: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
|
|
156
|
+
className = '',
|
|
157
|
+
children,
|
|
158
|
+
...props
|
|
159
|
+
}) => {
|
|
160
|
+
return (
|
|
161
|
+
<div className={`mt-4 pt-4 border-t border-gray-200 ${className}`} {...props}>
|
|
162
|
+
{children}
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
CardFooter.displayName = 'CardFooter';
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { InputHTMLAttributes, forwardRef } from 'react';
|
|
4
|
+
|
|
5
|
+
// Simple className merger utility
|
|
6
|
+
function cn(...classes: (string | undefined | null | false)[]): string {
|
|
7
|
+
return classes.filter(Boolean).join(' ');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// CHECKBOX COMPONENT
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Checkbox with label, error states, and accessibility
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
17
|
+
label?: string;
|
|
18
|
+
error?: string;
|
|
19
|
+
helperText?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
23
|
+
(
|
|
24
|
+
{
|
|
25
|
+
className,
|
|
26
|
+
label,
|
|
27
|
+
error,
|
|
28
|
+
helperText,
|
|
29
|
+
id,
|
|
30
|
+
disabled,
|
|
31
|
+
...props
|
|
32
|
+
},
|
|
33
|
+
ref
|
|
34
|
+
) => {
|
|
35
|
+
// Generate ID if not provided
|
|
36
|
+
const checkboxId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
|
|
37
|
+
const errorId = `${checkboxId}-error`;
|
|
38
|
+
const helperId = `${checkboxId}-helper`;
|
|
39
|
+
|
|
40
|
+
// Base checkbox styles
|
|
41
|
+
const baseStyles = [
|
|
42
|
+
'w-5',
|
|
43
|
+
'h-5',
|
|
44
|
+
'rounded',
|
|
45
|
+
'border-2',
|
|
46
|
+
'transition-all',
|
|
47
|
+
'duration-200',
|
|
48
|
+
'cursor-pointer',
|
|
49
|
+
'focus:outline-none',
|
|
50
|
+
'focus:ring-2',
|
|
51
|
+
'focus:ring-offset-2',
|
|
52
|
+
'disabled:opacity-50',
|
|
53
|
+
'disabled:cursor-not-allowed',
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
// State-based styles
|
|
57
|
+
const stateStyles = error
|
|
58
|
+
? [
|
|
59
|
+
'border-error-500',
|
|
60
|
+
'text-error-600',
|
|
61
|
+
'focus:ring-error-500',
|
|
62
|
+
]
|
|
63
|
+
: [
|
|
64
|
+
'border-gray-300',
|
|
65
|
+
'text-primary-600',
|
|
66
|
+
'focus:ring-primary-500',
|
|
67
|
+
'checked:bg-primary-600',
|
|
68
|
+
'checked:border-primary-600',
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div>
|
|
73
|
+
<div className="flex items-start gap-3">
|
|
74
|
+
{/* Checkbox */}
|
|
75
|
+
<input
|
|
76
|
+
ref={ref}
|
|
77
|
+
type="checkbox"
|
|
78
|
+
id={checkboxId}
|
|
79
|
+
className={cn(
|
|
80
|
+
...baseStyles,
|
|
81
|
+
...stateStyles,
|
|
82
|
+
className
|
|
83
|
+
)}
|
|
84
|
+
disabled={disabled}
|
|
85
|
+
aria-invalid={error ? 'true' : 'false'}
|
|
86
|
+
aria-describedby={cn(
|
|
87
|
+
error ? errorId : undefined,
|
|
88
|
+
helperText ? helperId : undefined
|
|
89
|
+
)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
|
|
93
|
+
{/* Label and helper text */}
|
|
94
|
+
{(label || helperText) && (
|
|
95
|
+
<div className="flex-1">
|
|
96
|
+
{label && (
|
|
97
|
+
<label
|
|
98
|
+
htmlFor={checkboxId}
|
|
99
|
+
className={cn(
|
|
100
|
+
'block',
|
|
101
|
+
'text-sm',
|
|
102
|
+
'font-medium',
|
|
103
|
+
'cursor-pointer',
|
|
104
|
+
error ? 'text-error-700' : 'text-gray-700',
|
|
105
|
+
disabled && 'opacity-50 cursor-not-allowed'
|
|
106
|
+
)}
|
|
107
|
+
>
|
|
108
|
+
{label}
|
|
109
|
+
</label>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
{helperText && !error && (
|
|
113
|
+
<p
|
|
114
|
+
id={helperId}
|
|
115
|
+
className="mt-0.5 text-sm text-gray-500"
|
|
116
|
+
>
|
|
117
|
+
{helperText}
|
|
118
|
+
</p>
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
)}
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
{/* Error message */}
|
|
125
|
+
{error && (
|
|
126
|
+
<p
|
|
127
|
+
id={errorId}
|
|
128
|
+
className="mt-1 ml-8 text-sm text-error-600"
|
|
129
|
+
role="alert"
|
|
130
|
+
>
|
|
131
|
+
{error}
|
|
132
|
+
</p>
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
Checkbox.displayName = 'Checkbox';
|
|
140
|
+
|
|
141
|
+
export { Checkbox };
|