> ## Documentation Index
> Fetch the complete documentation index at: https://docs.law4devs.eu/llms.txt
> Use this file to discover all available pages before exploring further.

import { useState, useEffect, useMemo } from 'react';

export const KW_STRINGS = {
  typescript: ' import from const let var async await for of new return if else true false null undefined typeof export class function this try catch finally throw break continue process console ',
  python: ' import from def return if else elif for in while class True False None and or not is as with try except finally raise pass break continue async await print os ',
  php: ' require_once use new class function return if else foreach while for echo true false null public private protected static abstract interface extends namespace getenv php ',
  dart: ' import package final var class abstract extends implements return if else for while try catch finally throw new this null true false void Future Stream await async print List Map String int bool ',
  java: ' import var class interface public private protected static final return if else for while try catch finally throw new this null true false void System List String ListOptions SearchOptions ',
  rust: ' use pub fn async await let mut if else for while match Ok Err Some None return struct impl true false Box ',
  curl: ' curl ',
};

export const TOKEN_COLORS = {
  keyword: '#FF7B72',
  string:  '#A5D6FF',
  comment: '#8B949E',
  number:  '#79C0FF',
  type:    '#FFA657',
  plain:   '#E6EDF3',
};

export function tokenize(code, lang) {
  const kwStr = KW_STRINGS[lang] || ' ';
  const tokens = [];
  const re = /\/\/[^\n]*|#[^\n]*|`(?:[^`\\]|\\.)*`|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\b\d+(?:\.\d+)?\b|\b[a-zA-Z_$][a-zA-Z0-9_$]*\b|[\s\S]/g;
  let m;
  while ((m = re.exec(code)) !== null) {
    const v = m[0];
    const c = v[0];
    let t = 'plain';
    if (c === '/' || c === '#') t = 'comment';
    else if (c === '"' || c === "'" || c === '`') t = 'string';
    else if (c >= '0' && c <= '9') t = 'number';
    else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c === '_' || c === '$') {
      if (kwStr.includes(' ' + v + ' ')) t = 'keyword';
      else if (c >= 'A' && c <= 'Z') t = 'type';
    }
    tokens.push({ t, v });
  }
  return tokens;
}

export const SNIPPETS = [
  {
    lang: 'TypeScript',
    icon: 'https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/typescript/typescript-original.svg',
    code: `import { Law4DevsClient } from 'law4devs';

const client = new Law4DevsClient({
  apiKey: process.env.LAW4DEVS_API_KEY!,
});

// List all CRA articles
const page = await client.articles.list('cra', { perPage: 5 });
console.log(\`\${page.meta.total} articles in CRA\`);

for (const article of page.data) {
  console.log(\`Art. \${article.articleNumber}: \${article.title}\`);
}

// Auto-paginate all GDPR articles
for await (const article of client.articles.iter('gdpr')) {
  console.log(article.articleNumber, article.title);
}`,
  },
  {
    lang: 'Python',
    icon: 'https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/python/python-original.svg',
    code: `import os
from law4devs import Law4DevsClient

client = Law4DevsClient(api_key=os.environ["LAW4DEVS_API_KEY"])

# Search across all frameworks
results = client.search.query(
    "incident notification 72 hours",
    frameworks=["nis2", "dora", "cra"],
)
print(f"Found {results.meta.total} results")

for r in results.data:
    print(f"{r.framework_slug.upper()} Art.{r.article_number}: {r.title}")

# Auto-paginate all NIS2 recitals
for recital in client.recitals.iter("nis2"):
    print(recital.number, recital.title)`,
  },
  {
    lang: 'PHP',
    icon: 'https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/php/php-original.svg',
    code: `<?php
require_once 'vendor/autoload.php';
use Law4Devs\\Client;

$client = new Client(apiKey: getenv('LAW4DEVS_API_KEY'));

// List first 5 CRA articles
$articles = $client->articles->list('cra', perPage: 5);
foreach ($articles->data as $article) {
    echo "Art. {$article->articleNumber}: {$article->title}";
}

// Auto-paginate all GDPR articles
foreach ($client->articles->iter('gdpr') as $article) {
    echo "{$article->articleNumber} {$article->title}";
}

// Search across all frameworks
$results = $client->search->query('data breach notification');
echo "Found {$results->meta->total} results";`,
  },
  {
    lang: 'Dart',
    icon: 'https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/dart/dart-original.svg',
    code: `import 'package:law4devs/law4devs.dart';

final client = Law4DevsClient(
  apiKey: Platform.environment['LAW4DEVS_API_KEY'],
);

// List first 5 CRA articles
final page = await client.articles.list('cra', perPage: 5);
print('\${page.meta.total} articles in CRA');

for (final article in page.data) {
  print('Art. \${article.number}: \${article.title}');
}

// Auto-paginate all GDPR articles
await for (final a in client.articles.iter('gdpr')) {
  print('\${a.number} \${a.title}');
}

// Search across all frameworks
final results = await client.search.query('incident notification 72 hours');
print('Found \${results.meta.total} results');`,
  },
  {
    lang: 'Java',
    icon: 'https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/java/java-original.svg',
    code: `import eu.law4devs.sdk.Law4DevsClient;
import eu.law4devs.sdk.models.ArticleSummary;

var client = Law4DevsClient.builder()
    .apiKey(System.getenv("LAW4DEVS_API_KEY"))
    .build();

// List first 5 CRA articles
var page = client.articles().list("cra", 1, 5);
System.out.println(page.meta().total() + " articles in CRA");

for (ArticleSummary article : page.data()) {
    System.out.println("Art. " + article.number()
        + ": " + article.title());
}

// Auto-paginate all GDPR articles
for (ArticleSummary a : client.articles().iter("gdpr")) {
    System.out.println(a.number() + " " + a.title());
}

// Search across all frameworks
var results = client.search().query("incident notification 72 hours");
System.out.println("Found " + results.meta().total() + " results");`,
  },
  {
    lang: 'Rust',
    icon: 'https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/rust/rust-original.svg',
    code: `use law4devs::Law4DevsClient;
use futures::StreamExt;

let client = Law4DevsClient::builder()
    .api_key(std::env::var("LAW4DEVS_API_KEY").unwrap_or_default())
    .build();

// List first 5 CRA articles
let page = client.articles.list("cra", None, Some(5)).await?;
println!("{} articles in CRA", page.meta.total);
for article in &page.data {
    println!("Art. {}: {}", article.article_number, article.title);
}

// Auto-paginate all GDPR articles
let mut stream = Box::pin(client.articles.iter("gdpr", 20));
while let Some(result) = stream.next().await {
    let a = result?;
    println!("{} {}", a.article_number, a.title);
}

// Search across all frameworks
let results = client.search
    .query("incident notification 72 hours", None, None, None, None).await?;
println!("Found {} results", results.meta.total);`,
  },
  {
    lang: 'curl',
    icon: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23E6EDF3' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='4 17 10 11 4 5'/%3E%3Cline x1='12' y1='19' x2='20' y2='19'/%3E%3C/svg%3E",
    code: `# List all supported frameworks
curl -H "X-API-Key: YOUR_API_KEY" \\
  https://api.law4devs.eu/v1/frameworks

# Get the first 5 CRA articles
curl -H "X-API-Key: YOUR_API_KEY" \\
  "https://api.law4devs.eu/v1/frameworks/cra/articles?per_page=5"

# Search for breach notification requirements
curl -H "X-API-Key: YOUR_API_KEY" \\
  "https://api.law4devs.eu/v1/search?q=breach+notification+72+hours"`,
  },
];

export const TypedCodePreview = () => {
  const [activeTab, setActiveTab] = useState(0);
  const [displayedCode, setDisplayedCode] = useState('');
  const [charIndex, setCharIndex] = useState(0);
  const [autoCycle, setAutoCycle] = useState(true);
  const [doneTyping, setDoneTyping] = useState(false);

  useEffect(() => {
    setDisplayedCode('');
    setCharIndex(0);
    setDoneTyping(false);
  }, [activeTab]);

  useEffect(() => {
    const full = SNIPPETS[activeTab].code;
    if (charIndex < full.length) {
      const t = setTimeout(() => {
        setDisplayedCode(full.slice(0, charIndex + 1));
        setCharIndex((c) => c + 1);
      }, 14);
      return () => clearTimeout(t);
    } else {
      setDoneTyping(true);
    }
  }, [charIndex, activeTab]);

  const highlighted = useMemo(
    () => tokenize(displayedCode, SNIPPETS[activeTab].lang.toLowerCase()),
    [displayedCode, activeTab]
  );

  useEffect(() => {
    if (!doneTyping || !autoCycle) return;
    const t = setTimeout(() => {
      setActiveTab((prev) => (prev + 1) % SNIPPETS.length);
    }, 2500);
    return () => clearTimeout(t);
  }, [doneTyping, autoCycle]);

  return (
    <div style={{ background: '#0D1117', borderRadius: '12px', overflow: 'hidden', marginBottom: '2rem', border: '1px solid #30363D' }}>
      <div style={{ display: 'flex', borderBottom: '1px solid #30363D', background: '#161B22', padding: '8px 12px', gap: '4px', flexWrap: 'wrap' }}>
        {SNIPPETS.map((s, i) => (
          <button
            key={i}
            onClick={() => { setActiveTab(i); setAutoCycle(false); }}
            title={s.lang}
            style={{
              width: '38px',
              height: '38px',
              padding: '0',
              borderRadius: '8px',
              border: '2px solid',
              borderColor: activeTab === i ? '#61DAFB' : 'transparent',
              cursor: 'pointer',
              background: activeTab === i ? '#21262D' : 'transparent',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              flexShrink: 0,
              boxSizing: 'border-box',
              transition: 'all 0.15s',
            }}
          >
            <div style={{ width: '22px', height: '22px', backgroundImage: `url("${s.icon}")`, backgroundSize: 'contain', backgroundRepeat: 'no-repeat', backgroundPosition: 'center' }} />
          </button>
        ))}
      </div>
      <pre
        style={{
          margin: 0,
          padding: '20px 24px',
          overflowX: 'auto',
          minHeight: '260px',
          fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", monospace',
          fontSize: '13px',
          lineHeight: 1.7,
          color: '#E6EDF3',
          background: 'transparent',
        }}
      >
        <code style={{ whiteSpace: 'pre' }}>
          {highlighted.map((tok, i) => (
            <span key={i} style={{ color: TOKEN_COLORS[tok.t] }}>{tok.v}</span>
          ))}
          {!doneTyping && (
            <span
              style={{
                display: 'inline-block',
                width: '2px',
                height: '1em',
                background: '#61DAFB',
                marginLeft: '1px',
                verticalAlign: 'middle',
                animation: 'blink-caret 0.75s step-end infinite',
              }}
            />
          )}
        </code>
      </pre>
      <style>{`@keyframes blink-caret { from, to { opacity: 1; } 50% { opacity: 0; } }`}</style>
    </div>
  );
};

<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', padding: '2.5rem 0 2rem' }}>
  <img src="https://mintcdn.com/law4devs/bxEZIRxZDtvCoe6M/logo/logo.png?fit=max&auto=format&n=bxEZIRxZDtvCoe6M&q=85&s=399899ded88b25190661cb8ad43b8b49" alt="Law4Devs" style={{ height: '80px', marginBottom: '1.5rem' }} width="452" height="434" data-path="logo/logo.png" />

  <div
    style={{
fontFamily: '"Syne", "Space Grotesk", system-ui, sans-serif',
fontSize: '3.25rem',
fontWeight: 800,
lineHeight: 1.1,
letterSpacing: '-0.02em'
}}
  >
    Law<span style={{ color: '#61DAFB' }}>4</span>Devs
  </div>

  <p style={{ marginTop: '0.75rem', fontSize: '1.1rem', color: '#64748B', maxWidth: '480px' }}>
    Structured EU regulatory compliance data for developers
  </p>
</div>

## What is Law4Devs?

Law4Devs is a REST API and SDKs that turns EU regulatory texts into structured, queryable JSON. Instead of reading 300-page PDF regulations, your application queries articles, recitals, requirements, compliance deadlines, and tags via simple HTTP calls.

**19 EU frameworks** — CRA, GDPR, NIS2, DORA, AI Act, eIDAS 2.0, DSA, DMA, Data Act, MiCA, and more.

<img src="https://res.cloudinary.com/dp9q7kbap/image/upload/v1773262739/how-it-works_tumqd2.png" alt="How It Works" style={{ width: '100%', borderRadius: '12px', marginBottom: '2rem' }} />

<TypedCodePreview />

<CardGroup cols={2}>
  <Card title="Python SDK" icon="python" color="#3776AB" href="/sdks/python/installation">
    Zero-dependency. `pip install law4devs`
  </Card>

  <Card title="TypeScript SDK" icon="js" color="#3178C6" href="/sdks/typescript/installation">
    Zero-dependency. `npm install law4devs`
  </Card>

  <Card title="PHP SDK" icon="php" color="#777BB4" href="/sdks/php/installation">
    Composer package. `composer require law4devs/law4devs`
  </Card>

  <Card title="Java SDK" icon="java" color="#ED8B00" href="/sdks/java/installation">
    Zero-dependency. Maven · Java 17+
  </Card>

  <Card title="Flutter SDK" icon="mobile" color="#02569B" href="/sdks/flutter/installation">
    pub.dev · Dart 3+ · Flutter & CLI
  </Card>

  <Card title="Rust SDK" icon="rust" color="#CE422B" href="/sdks/rust/installation">
    crates.io · Rust 1.85+ · Tokio async
  </Card>

  <Card title="API Reference" icon="code" color="#8B5CF6" href="/api-reference">
    Interactive docs for all 21 endpoints.
  </Card>

  <Card title="Supported Frameworks" icon="building-columns" color="#0EA5E9" href="/frameworks">
    All 19 EU regulations, with CELEX numbers.
  </Card>
</CardGroup>
