{"_id":"@damarkuncoro/ui-renderers","_rev":"2-1cb2cf5d341f0bfb93e8f748b9675529","name":"@damarkuncoro/ui-renderers","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@damarkuncoro/ui-renderers","version":"0.1.0","keywords":["ui","renderers","contracts","react","typescript","cdma"],"author":{"name":"DAMAR KUNCORO"},"license":"MIT","_id":"@damarkuncoro/ui-renderers@0.1.0","maintainers":[{"name":"damarkuncoro","email":"damarkuncoro@gmail.com"}],"homepage":"https://github.com/damarkuncoro/contract-architecture#readme","bugs":{"url":"https://github.com/damarkuncoro/contract-architecture/issues"},"dist":{"shasum":"b29772afdc30ed32d4ab6276702e1b5a3e6d04d4","tarball":"https://registry.npmjs.org/@damarkuncoro/ui-renderers/-/ui-renderers-0.1.0.tgz","fileCount":288,"integrity":"sha512-CdgCc2J7n2ubZcyJK0HnXfRGqXqNzG4jEIc13XGRsS/DUAGvDpnsuKY/SmMptGZ82CNh1RKdPG6woIm3MWROQQ==","signatures":[{"sig":"MEUCIQDpciS+KsTta4M+XtS55gWUZNOknU4t0abv6mwpzvHYUwIgB1ICNLWFOu29YBqzSefUTWQHI10L/iVpJ3r7Y9Ydqi0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":997578},"main":"lib/index.cjs","type":"module","types":"lib/index.d.ts","module":"lib/index.js","exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js","require":"./lib/index.cjs"}},"gitHead":"9306bbf856d5088066f17ef04267135ddf91e7eb","scripts":{"dev":"rollup -c -w","lint":"eslint src --ext .ts,.tsx","test":"vitest","build":"tsc --emitDeclarationOnly && rollup -c","clean":"rm -rf lib","type-check":"tsc --noEmit"},"_npmUser":{"name":"damarkuncoro","email":"damarkuncoro@gmail.com"},"repository":{"url":"git+https://github.com/damarkuncoro/contract-architecture.git","type":"git","directory":"examples/react-renderer/packages/renderers"},"_npmVersion":"10.8.2","description":"Contract-driven React renderers for the CDMA architecture","directories":{},"_nodeVersion":"20.19.4","dependencies":{"clsx":"^2.1.0","tailwind-merge":"^2.2.0"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^24.0.0","eslint":"^8.0.0","rollup":"^4.0.0","vitest":"^1.2.0","typescript":"^5.0.0","@types/react":"^18.0.0","@types/react-dom":"^18.0.0","rollup-plugin-dts":"^6.0.0","@vitest/coverage-v8":"^1.2.0","@testing-library/react":"^16.3.2","@rollup/plugin-commonjs":"^25.0.0","@rollup/plugin-typescript":"^11.0.0","@testing-library/jest-dom":"^6.9.1","@rollup/plugin-node-resolve":"^15.0.0"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@damarkuncoro/ui-core":"^0.1.0","@damarkuncoro/ui-components":"^0.1.0","@damarkuncoro/meta-architecture":"^2.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ui-renderers_0.1.0_1769684216072_0.47730254049838816","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@damarkuncoro/ui-renderers","version":"0.1.2","description":"Contract-driven React renderers for the CDMA architecture","type":"module","main":"lib/index.cjs","module":"lib/index.js","types":"lib/index.d.ts","exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js","require":"./lib/index.cjs"}},"scripts":{"build":"tsc --project tsconfig.build.json --emitDeclarationOnly && rollup -c","dev":"rollup -c -w","test":"vitest","lint":"eslint src --ext .ts,.tsx","type-check":"tsc --noEmit","clean":"rm -rf lib"},"keywords":["ui","renderers","contracts","react","typescript","cdma"],"author":{"name":"DAMAR KUNCORO"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/damarkuncoro/contract-architecture.git","directory":"examples/react-renderer/packages/renderers"},"dependencies":{"clsx":"^2.1.0","tailwind-merge":"^2.2.0"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@damarkuncoro/ui-core":"^0.1.3","@damarkuncoro/ui-components":"^0.1.1","@damarkuncoro/meta-architecture":"^2.0.0"},"devDependencies":{"@rollup/plugin-commonjs":"^25.0.0","@rollup/plugin-node-resolve":"^15.0.0","@rollup/plugin-typescript":"^11.0.0","@testing-library/jest-dom":"^6.9.1","@testing-library/react":"^16.3.2","@types/react":"^18.0.0","@types/react-dom":"^18.0.0","@typescript-eslint/eslint-plugin":"^8.54.0","@typescript-eslint/parser":"^8.54.0","@vitest/coverage-v8":"^1.2.0","eslint":"^8.0.0","jsdom":"^24.0.0","rollup":"^4.0.0","rollup-plugin-dts":"^6.0.0","typescript":"^5.0.0","vitest":"^1.2.0"},"_id":"@damarkuncoro/ui-renderers@0.1.2","gitHead":"4c166a4a13d6b7d6ead55977652451a459ae1e83","bugs":{"url":"https://github.com/damarkuncoro/contract-architecture/issues"},"homepage":"https://github.com/damarkuncoro/contract-architecture#readme","_nodeVersion":"20.19.4","_npmVersion":"10.8.2","dist":{"integrity":"sha512-nMvdamnv5YgjbKjs4O2AtfHTPR7adUjeeooUXUNdOZgvkLVzQBULN2tGC0aV2zoYysOP5FxlyzP/fDPVq/8mlw==","shasum":"6af5247282f631fc7a9f7795c769f674fceef9fc","tarball":"https://registry.npmjs.org/@damarkuncoro/ui-renderers/-/ui-renderers-0.1.2.tgz","fileCount":292,"unpackedSize":1111319,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBwR3HsvcLPipfBcxjckGnyqcqz7gEOKL5Wt/cGwzRSpAiBZu6EAaIN31bnWr5DpGfFkDNgStYBKxGz6CO5fgHTOqQ=="}]},"_npmUser":{"name":"damarkuncoro","email":"damarkuncoro@gmail.com"},"directories":{},"maintainers":[{"name":"damarkuncoro","email":"damarkuncoro@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ui-renderers_0.1.2_1769767232274_0.6620400369098407"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-29T10:56:56.000Z","modified":"2026-01-30T10:00:32.543Z","0.1.0":"2026-01-29T10:56:56.275Z","0.1.2":"2026-01-30T10:00:32.437Z"},"bugs":{"url":"https://github.com/damarkuncoro/contract-architecture/issues"},"author":{"name":"DAMAR KUNCORO"},"license":"MIT","homepage":"https://github.com/damarkuncoro/contract-architecture#readme","keywords":["ui","renderers","contracts","react","typescript","cdma"],"repository":{"type":"git","url":"git+https://github.com/damarkuncoro/contract-architecture.git","directory":"examples/react-renderer/packages/renderers"},"description":"Contract-driven React renderers for the CDMA architecture","maintainers":[{"name":"damarkuncoro","email":"damarkuncoro@gmail.com"}],"readme":"# @damarkuncoro/ui-renderers\n\nDynamic component renderers for contract-based UI generation, enabling runtime component creation from configuration.\n\n## 📦 Installation\n\n```bash\nnpm install @damarkuncoro/ui-renderers @damarkuncoro/ui-core @damarkuncoro/ui-components\n```\n\n## 🎯 What are Renderers?\n\nRenderers enable dynamic UI generation based on contracts. Instead of hardcoding components, you define UI structure through configuration that gets rendered at runtime.\n\n### Key Benefits\n\n- **Dynamic UI**: Generate interfaces from configuration\n- **Contract Compliance**: Automatic validation against contracts\n- **Runtime Flexibility**: Change UI without code redeployment\n- **Type Safety**: Full TypeScript support with contract validation\n\n## 🚀 Basic Usage\n\n### Simple Component Rendering\n\n```tsx\nimport { ContractRenderer } from '@damarkuncoro/ui-renderers';\nimport { buttonContract } from '@damarkuncoro/ui-core/contracts';\n\nfunction DynamicButton() {\n  const runtimeProps = {\n    variant: 'primary',\n    size: 'md',\n    children: 'Click me',\n    onClick: () => console.log('Button clicked!')\n  };\n\n  return (\n    <ContractRenderer\n      contract={buttonContract}\n      runtimeProps={runtimeProps}\n    />\n  );\n}\n```\n\n### Form Generation\n\n```tsx\nimport { ContractRenderer } from '@damarkuncoro/ui-renderers';\nimport { formContract } from '@damarkuncoro/ui-core/contracts';\n\nconst formConfig = {\n  fields: [\n    {\n      contract: 'input',\n      props: {\n        name: 'email',\n        type: 'email',\n        label: 'Email Address',\n        required: true,\n        placeholder: 'Enter your email'\n      }\n    },\n    {\n      contract: 'input',\n      props: {\n        name: 'password',\n        type: 'password',\n        label: 'Password',\n        required: true\n      }\n    },\n    {\n      contract: 'button',\n      props: {\n        type: 'submit',\n        variant: 'primary',\n        children: 'Login'\n      }\n    }\n  ]\n};\n\nfunction DynamicForm() {\n  return (\n    <ContractRenderer\n      contract={formContract}\n      runtimeProps={formConfig}\n    />\n  );\n}\n```\n\n## 🏗️ Architecture\n\n### Contract-Based Rendering\n\n```\nContract Definition → Renderer Map → Component Instance\n       ↓                    ↓              ↓\n   Validation    →   Resolution   →   Rendering\n```\n\n### Renderer Resolution\n\n```typescript\n// Renderer map connects contracts to components\nconst rendererMap = {\n  'ui-button': ButtonRenderer,\n  'ui-input': InputRenderer,\n  'ui-card': CardRenderer,\n  // ... more mappings\n};\n```\n\n## 📋 Advanced Usage\n\n### Custom Renderers\n\n```tsx\nimport { createRenderer } from '@damarkuncoro/ui-renderers';\n\n// Create custom renderer\nconst CustomCardRenderer = createRenderer({\n  contractId: 'custom-card',\n  component: ({ title, content, ...props }) => (\n    <div className=\"custom-card\" {...props}>\n      <h3 className=\"custom-title\">{title}</h3>\n      <div className=\"custom-content\">{content}</div>\n    </div>\n  ),\n  validate: (props) => {\n    // Custom validation logic\n    if (!props.title) {\n      throw new Error('Title is required for custom card');\n    }\n  }\n});\n\n// Register custom renderer\nregisterRenderer('custom-card', CustomCardRenderer);\n```\n\n### Dynamic Page Generation\n\n```tsx\nimport { PageRenderer } from '@damarkuncoro/ui-renderers';\n\nconst pageConfig = {\n  layout: 'dashboard',\n  sections: [\n    {\n      type: 'stats',\n      components: [\n        { contract: 'stats-card', props: { title: 'Revenue', value: '$45,231' } },\n        { contract: 'stats-card', props: { title: 'Users', value: '12,234' } }\n      ]\n    },\n    {\n      type: 'content',\n      components: [\n        { contract: 'table', props: { data: tableData, columns: tableColumns } }\n      ]\n    }\n  ]\n};\n\nfunction DynamicPage() {\n  return <PageRenderer config={pageConfig} />;\n}\n```\n\n### Conditional Rendering\n\n```tsx\nconst conditionalConfig = {\n  condition: 'user.role === \"admin\"',\n  components: [\n    {\n      contract: 'button',\n      props: { children: 'Admin Panel', variant: 'primary' }\n    }\n  ],\n  fallback: {\n    contract: 'text',\n    props: { children: 'Access denied' }\n  }\n};\n\n<ConditionalRenderer config={conditionalConfig} context={{ user }} />\n```\n\n## 🔧 Renderer API\n\n### ContractRenderer\n\n```typescript\ninterface ContractRendererProps {\n  contract: ContractEntity;\n  runtimeProps?: Record<string, any>;\n  context?: Record<string, any>;\n  onError?: (error: Error) => void;\n  onSuccess?: (result: any) => void;\n}\n```\n\n### PageRenderer\n\n```typescript\ninterface PageRendererProps {\n  config: PageConfig;\n  context?: Record<string, any>;\n  theme?: string;\n  skin?: string;\n}\n\ninterface PageConfig {\n  layout?: string;\n  sections: SectionConfig[];\n}\n\ninterface SectionConfig {\n  type: string;\n  components: ComponentConfig[];\n}\n\ninterface ComponentConfig {\n  contract: string;\n  props: Record<string, any>;\n  condition?: string;\n}\n```\n\n## 🎨 Integration with Themes\n\n### Theme-Aware Rendering\n\n```tsx\nimport { ThemeProvider } from '@damarkuncoro/ui-themes';\nimport { ContractRenderer } from '@damarkuncoro/ui-renderers';\n\nfunction ThemedDynamicComponent() {\n  return (\n    <ThemeProvider skin=\"metronic\">\n      <ContractRenderer\n        contract={componentContract}\n        runtimeProps={componentProps}\n      />\n    </ThemeProvider>\n  );\n}\n```\n\n### Skin-Specific Rendering\n\n```tsx\n// Renderer can adapt based on active theme\nconst adaptiveRenderer = ({ contract, runtimeProps, theme }) => {\n  const skin = theme.skin || 'default';\n\n  // Different rendering logic per skin\n  switch (skin) {\n    case 'metronic':\n      return <MetronicComponent {...runtimeProps} />;\n    case 'material':\n      return <MaterialComponent {...runtimeProps} />;\n    default:\n      return <DefaultComponent {...runtimeProps} />;\n  }\n};\n```\n\n## 🔒 Validation & Error Handling\n\n### Contract Validation\n\n```tsx\nimport { validateContractProps } from '@damarkuncoro/ui-renderers';\n\nconst contract = buttonContract;\nconst runtimeProps = { variant: 'invalid-variant' };\n\ntry {\n  const validatedProps = validateContractProps(contract, runtimeProps);\n  // Render with validated props\n} catch (error) {\n  console.error('Validation failed:', error.message);\n  // Fallback rendering or error display\n}\n```\n\n### Error Boundaries\n\n```tsx\nimport { RendererErrorBoundary } from '@damarkuncoro/ui-renderers';\n\nfunction SafeRenderer({ contract, runtimeProps }) {\n  return (\n    <RendererErrorBoundary\n      fallback={(error) => (\n        <div className=\"error-fallback\">\n          Failed to render component: {error.message}\n        </div>\n      )}\n    >\n      <ContractRenderer\n        contract={contract}\n        runtimeProps={runtimeProps}\n      />\n    </RendererErrorBoundary>\n  );\n}\n```\n\n## 📊 Performance Optimization\n\n### Memoization\n\n```tsx\nimport { memoizedRenderer } from '@damarkuncoro/ui-renderers';\n\n// Automatically memoizes rendered components\nconst MemoizedContractRenderer = memoizedRenderer(ContractRenderer);\n```\n\n### Lazy Loading\n\n```tsx\nimport { lazyRenderer } from '@damarkuncoro/ui-renderers';\n\n// Load components on demand\nconst LazyButtonRenderer = lazyRenderer(() =>\n  import('./ButtonRenderer')\n);\n```\n\n### Renderer Caching\n\n```tsx\nimport { createRendererCache } from '@damarkuncoro/ui-renderers';\n\nconst rendererCache = createRendererCache();\n\n// Cache rendered components\nconst cachedRenderer = rendererCache.get(contract.id) ||\n  rendererCache.set(contract.id, createRenderer(contract));\n```\n\n## 🧪 Testing Renderers\n\n### Unit Testing\n\n```tsx\nimport { render, screen } from '@testing-library/react';\nimport { ContractRenderer } from '@damarkuncoro/ui-renderers';\nimport { buttonContract } from '@damarkuncoro/ui-core/contracts';\n\ntest('renders button from contract', () => {\n  const runtimeProps = {\n    children: 'Test Button',\n    onClick: jest.fn()\n  };\n\n  render(\n    <ContractRenderer\n      contract={buttonContract}\n      runtimeProps={runtimeProps}\n    />\n  );\n\n  const button = screen.getByRole('button', { name: 'Test Button' });\n  expect(button).toBeInTheDocument();\n});\n```\n\n### Integration Testing\n\n```tsx\nimport { render, fireEvent, waitFor } from '@testing-library/react';\nimport { FormRenderer } from '@damarkuncoro/ui-renderers';\n\ntest('form submission works', async () => {\n  const onSubmit = jest.fn();\n  const formConfig = {\n    fields: [\n      { contract: 'input', props: { name: 'email', required: true } },\n      { contract: 'button', props: { type: 'submit', children: 'Submit' } }\n    ],\n    onSubmit\n  };\n\n  render(<FormRenderer config={formConfig} />);\n\n  const emailInput = screen.getByLabelText('email');\n  const submitButton = screen.getByRole('button', { name: 'Submit' });\n\n  fireEvent.change(emailInput, { target: { value: 'test@example.com' } });\n  fireEvent.click(submitButton);\n\n  await waitFor(() => {\n    expect(onSubmit).toHaveBeenCalledWith({\n      email: 'test@example.com'\n    });\n  });\n});\n```\n\n## 🔧 Advanced Features\n\n### Custom Renderer Plugins\n\n```tsx\nimport { createRendererPlugin } from '@damarkuncoro/ui-renderers';\n\n// Create analytics plugin\nconst analyticsPlugin = createRendererPlugin({\n  name: 'analytics',\n  beforeRender: (contract, props) => {\n    // Track component render\n    analytics.track('component_render', {\n      contractId: contract.id,\n      props: Object.keys(props)\n    });\n  },\n  afterRender: (contract, element) => {\n    // Add tracking attributes\n    return React.cloneElement(element, {\n      'data-analytics-id': contract.id\n    });\n  }\n});\n\n// Register plugin\nregisterRendererPlugin(analyticsPlugin);\n```\n\n### Internationalization (i18n)\n\n```tsx\nimport { createI18nRenderer } from '@damarkuncoro/ui-renderers';\n\nconst i18nRenderer = createI18nRenderer({\n  locale: 'id',\n  translations: {\n    'button.submit': 'Kirim',\n    'input.placeholder': 'Masukkan teks...'\n  }\n});\n\n// Use i18n-aware renderer\n<i18nRenderer\n  contract={buttonContract}\n  runtimeProps={{\n    children: 'button.submit', // Will be translated\n    placeholder: 'input.placeholder'\n  }}\n/>\n```\n\n### Server-Side Rendering (SSR)\n\n```tsx\nimport { renderToString } from 'react-dom/server';\nimport { SSRContractRenderer } from '@damarkuncoro/ui-renderers';\n\nfunction renderPage(config) {\n  const html = renderToString(\n    <SSRContractRenderer config={config} />\n  );\n\n  return `\n    <!DOCTYPE html>\n    <html>\n      <body>\n        <div id=\"root\">${html}</div>\n        <script src=\"/client.js\"></script>\n      </body>\n    </html>\n  `;\n}\n```\n\n## 📚 Use Cases\n\n### CMS-Driven Interfaces\n\n```typescript\n// Content Management System integration\nconst cmsConfig = await fetch('/api/page-config').then(r => r.json());\n\nfunction CMSPage() {\n  return (\n    <PageRenderer\n      config={cmsConfig}\n      context={{ user, permissions }}\n    />\n  );\n}\n```\n\n### A/B Testing Components\n\n```typescript\n// Dynamic component testing\nconst experimentConfig = {\n  experimentId: 'button-color-test',\n  variants: {\n    control: { contract: 'button', props: { variant: 'primary' } },\n    variant1: { contract: 'button', props: { variant: 'success' } }\n  }\n};\n\n<ExperimentRenderer config={experimentConfig} />\n```\n\n### Progressive Web Apps (PWA)\n\n```typescript\n// Offline-capable dynamic UI\nconst offlineConfig = {\n  fallback: {\n    contract: 'offline-message',\n    props: { message: 'You are currently offline' }\n  },\n  components: isOnline ? onlineComponents : offlineComponents\n};\n\n<ProgressiveRenderer config={offlineConfig} />\n```\n\n## 🔄 Migration Guide\n\n### From Static to Dynamic Rendering\n\n```tsx\n// Before: Static component\nfunction UserProfile({ user }) {\n  return (\n    <Card>\n      <Avatar src={user.avatar} />\n      <div>\n        <h3>{user.name}</h3>\n        <p>{user.email}</p>\n      </div>\n    </Card>\n  );\n}\n\n// After: Contract-based rendering\nconst userProfileConfig = {\n  contract: 'card',\n  props: {\n    children: [\n      {\n        contract: 'avatar',\n        props: { src: '{{user.avatar}}' }\n      },\n      {\n        contract: 'stack',\n        props: {\n          children: [\n            { contract: 'text', props: { variant: 'h3', children: '{{user.name}}' } },\n            { contract: 'text', props: { children: '{{user.email}}' } }\n          ]\n        }\n      }\n    ]\n  }\n};\n\nfunction DynamicUserProfile({ user }) {\n  return (\n    <ContractRenderer\n      contract={cardContract}\n      runtimeProps={userProfileConfig.props}\n      context={{ user }}\n    />\n  );\n}\n```\n## 🤝 Contributing\n\nWhen contributing to renderers:\n\n1. **Performance**: Optimize rendering logic\n2. **Error Handling**: Comprehensive error boundaries\n3. **Type Safety**: Full TypeScript coverage\n4. **Testing**: Both unit and integration tests\n5. **Documentation**: Include usage examples\n\n## 📄 License\n\nMIT License - see [LICENSE](../../LICENSE) file for details.\n","readmeFilename":"README.md"}