@urbicon-ui/design-content 6.3.1 → 6.3.3

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.
@@ -18,6 +18,7 @@ Sends POST to `apiPath` (default `/api/auth/register`). Pair with `createRegiste
18
18
  | apiPath | `string` | no | '/api/auth/register' | ApiPath property for the RegisterPage component |
19
19
  | class | `string` | no | | Extra classes on the root element. |
20
20
  | csrf | `CsrfClientOptions` | no | | CSRF cookie/header names — only needed when the server overrides the defaults via `config.csrf`. Mutating requests echo the token automatically. |
21
+ | defaultEmail | `string` | no | '' | Pre-fills the email field. Pass the `?email=` query param from the invitation link (`createInvitationHandlers` builds `/auth/register?email=<invitee>`) so an invited user lands on a ready-to-submit form instead of retyping — and a typo can't trigger the opaque "invitation required" 403. Following the same explicit-prop pattern as `ResetPasswordPage`/`VerifyEmailPage`'s `token`, read it from the page in your route (SSR-safe), e.g. `defaultEmail={page.url.searchParams.get('email') ?? ''}`. |
21
22
  | fetcher | `typeof globalThis.fetch` | no | | Custom fetch implementation for all API calls. Defaults to the global `fetch`. Useful for mock backends in demos/tests or custom retry/auth layers. |
22
23
  | footer | `Snippet` | no | | Content rendered below the form, above links (e.g. terms checkbox). |
23
24
  | header | `Snippet` | no | | Content rendered above the form (e.g. social login buttons). |
@@ -0,0 +1,49 @@
1
+
2
+ ---
3
+
4
+ ## DateRangePicker
5
+ Date range picker with a dual-calendar popup for selecting a start and end date — min/max constraints, disabled dates, and native form submission via paired hidden inputs.
6
+
7
+ **Import:** `import { DateRangePicker } from '@urbicon-ui/blocks';`
8
+
9
+ ### Api
10
+ | Prop | Type | Required | Default | Description |
11
+ | --- | --- | :---: | --- | --- |
12
+ | ...HTMLAttributes<HTMLDivElement> | `HTMLAttributes` | no | | HTML attributes (excluding: 'children') |
13
+ | calendarVariant | `'default' | 'bordered' | 'ghost'` | no | | calendarVariant property |
14
+ | class | `string` | no | | Additional CSS classes to apply to the DateRangePicker component |
15
+ | clearable | `boolean` | no | | Clearable property for the DateRangePicker component |
16
+ | closeOnClickOutside | `boolean` | no | true | Whether the popover closes on outside click. |
17
+ | closeOnEscape | `boolean` | no | true | Whether the popover closes on Escape key. |
18
+ | closeOnSelect | `boolean` | no | true | Close popover after selecting both dates. |
19
+ | defaultMonth | `MonthIndex` | no | | Default month shown when the picker opens without a value. `0`–`11`. |
20
+ | defaultYear | `number` | no | | Default year shown when the picker opens without a value. |
21
+ | disabled | `boolean` | no | | Whether the DateRangePicker is disabled and non-interactive |
22
+ | disabledDates | `Date[]` | no | | disabledDates property |
23
+ | displayFormat | `DateFormatOptions` | no | | Intl.DateTimeFormat options for displayed dates. |
24
+ | error | `string` | no | | Error property for the DateRangePicker component |
25
+ | fixedWeeks | `boolean` | no | | FixedWeeks property for the DateRangePicker component |
26
+ | helper | `string` | no | | Helper property for the DateRangePicker component |
27
+ | inputVariant | `'outlined' | 'filled' | 'ghost' | 'underline'` | no | | inputVariant property |
28
+ | isDateDisabled | `(date: Date) => boolean` | no | | Predicate that disables specific dates. Throws are caught and logged; the date is then treated as allowed. |
29
+ | label | `string` | no | | Label above the input. |
30
+ | locale | `string` | no | | Locale property for the DateRangePicker component |
31
+ | maxDate | `Date` | no | | MaxDate property for the DateRangePicker component |
32
+ | minDate | `Date` | no | | MinDate property for the DateRangePicker component |
33
+ | mint | `MintProp` | no | | Micro-interaction configuration for enhanced user experience |
34
+ | name | `string` | no | | Shared base `name` for native form submission. When set, two hidden inputs are rendered — `{name}_start` and `{name}_end` — each carrying the serialized date, so the visible input's locale-formatted display string is never submitted instead. Empty range submits both halves as `""`. The `_start` / `_end` convention reflects the picker's domain language — date ranges read naturally as start/end rather than min/max. |
35
+ | onClickOutside | `() => void` | no | | Notification only — does NOT govern close behavior. |
36
+ | onEscape | `() => void` | no | | Notification only — does NOT govern close behavior. |
37
+ | onOpenChange | `(open: boolean) => void` | no | | onOpenChange property |
38
+ | onValueChange | `(value: DateRange | undefined) => void` | no | | Fires when the selected range changes. During calendar selection the user clicks twice — once to set the start, once to set the end. `onValueChange` only fires when the range is *complete* (start ≠ end); the intermediate `{ start: d, end: d }` state does NOT fire this callback. Use `bind:value` if you need the in-progress state. |
39
+ | placeholder | `string` | no | | Placeholder when no range is selected. |
40
+ | required | `boolean` | no | | Required property for the DateRangePicker component |
41
+ | showOutsideDays | `boolean` | no | | showOutsideDays property |
42
+ | showWeekNumbers | `boolean` | no | | showWeekNumbers property |
43
+ | size | `'xs' | 'sm' | 'md' | 'lg' | 'xl'` | no | | Size variant that controls dimensions and spacing of the DateRangePicker |
44
+ | value | `DateRange` | no | | Currently selected date range. Supports bind:value. |
45
+ | valueFormat | `'date' | 'iso'` | no | 'date' | Format used to serialise both range halves. See for semantics. |
46
+ | weekStartsOn | `WeekdayIndex` | no | | weekStartsOn property |
47
+
48
+ Inherited from:
49
+ - Omit<HTMLAttributes<HTMLDivElement>, 'children'> (omit-pattern)
@@ -1,5 +1,5 @@
1
1
  {
2
- "generated": "2026-06-23T14:32:43.820Z",
2
+ "generated": "2026-06-24T07:50:05.631Z",
3
3
  "version": "0.2.38",
4
4
  "components": [
5
5
  {
@@ -1358,6 +1358,53 @@
1358
1358
  "Input"
1359
1359
  ]
1360
1360
  },
1361
+ {
1362
+ "name": "DateRangePicker",
1363
+ "slug": "date-range-picker",
1364
+ "package": "@urbicon-ui/blocks",
1365
+ "group": "components",
1366
+ "description": "Date range picker with a dual-calendar popup for selecting a start and end date — min/max constraints, disabled dates, and native form submission via paired hidden inputs.",
1367
+ "tags": [
1368
+ "form"
1369
+ ],
1370
+ "import": "import { DateRangePicker } from '@urbicon-ui/blocks';",
1371
+ "llmTxtPath": "components/date-range-picker/llm.txt",
1372
+ "variants": [],
1373
+ "keyProps": [
1374
+ "calendarVariant",
1375
+ "class",
1376
+ "clearable",
1377
+ "closeOnClickOutside",
1378
+ "closeOnEscape",
1379
+ "closeOnSelect",
1380
+ "defaultMonth",
1381
+ "defaultYear"
1382
+ ],
1383
+ "keyPropTypes": {
1384
+ "calendarVariant": "'default' | 'bordered' | 'ghost'",
1385
+ "defaultMonth": "MonthIndex",
1386
+ "disabledDates": "Date[]",
1387
+ "displayFormat": "DateFormatOptions",
1388
+ "inputVariant": "'outlined' | 'filled' | 'ghost' | 'underline'",
1389
+ "isDateDisabled": "(date: Date) => boolean",
1390
+ "maxDate": "Date",
1391
+ "minDate": "Date",
1392
+ "onClickOutside": "() => void",
1393
+ "onEscape": "() => void",
1394
+ "onOpenChange": "(open: boolean) => void",
1395
+ "onValueChange": "(value: DateRange | undefined) => void",
1396
+ "size": "'xs' | 'sm' | 'md' | 'lg' | 'xl'",
1397
+ "value": "DateRange",
1398
+ "valueFormat": "'date' | 'iso'",
1399
+ "weekStartsOn": "WeekdayIndex"
1400
+ },
1401
+ "slots": [],
1402
+ "hasExamples": false,
1403
+ "relatedComponents": [
1404
+ "DatePicker",
1405
+ "Calendar"
1406
+ ]
1407
+ },
1361
1408
  {
1362
1409
  "name": "Dialog",
1363
1410
  "slug": "dialog",
@@ -2923,11 +2970,11 @@
2923
2970
  "apiPath",
2924
2971
  "class",
2925
2972
  "csrf",
2973
+ "defaultEmail",
2926
2974
  "fetcher",
2927
2975
  "footer",
2928
2976
  "header",
2929
- "links",
2930
- "loginUrl"
2977
+ "links"
2931
2978
  ],
2932
2979
  "keyPropTypes": {
2933
2980
  "csrf": "CsrfClientOptions",
@@ -4481,7 +4528,7 @@
4481
4528
  "Progress",
4482
4529
  "Tooltip"
4483
4530
  ],
4484
- "code": "<script lang=\"ts\">\n import {\n Avatar, Badge, Button, Card, Progress, Tooltip,\n SidebarLayout, MenuIcon, HomeIcon, BarChartIcon, UsersIcon, SettingsIcon\n } from '@urbicon-ui/blocks';\n\n let sidebarOpen = $state(false);\n let activeRoute = $state('dashboard');\n\n const navItems = [\n { id: 'dashboard', label: 'Dashboard', icon: HomeIcon },\n { id: 'analytics', label: 'Analytics', icon: BarChartIcon },\n { id: 'users', label: 'Users', icon: UsersIcon },\n { id: 'settings', label: 'Settings', icon: SettingsIcon }\n ];\n\n const stats = [\n { label: 'Total Users', value: '12,847', change: '+12.5%', intent: 'success' as const, progress: 78, tooltip: 'Target: 16,500 users by Q2' },\n { label: 'Revenue', value: '$48,392', change: '+8.2%', intent: 'success' as const, progress: 64, tooltip: 'Target: $75,000 monthly' },\n { label: 'Active Sessions', value: '1,429', change: '-3.1%', intent: 'danger' as const, progress: 45, tooltip: 'Down from 1,475 last week' },\n { label: 'Conversion', value: '3.24%', change: '+0.8%', intent: 'success' as const, progress: 81, tooltip: 'Target: 4.0% conversion rate' }\n ];\n\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const chartData = [40, 65, 45, 80, 55, 70, 85, 60, 90, 75, 95, 88];\n\n const recentActivity = [\n { user: 'Sarah Chen', action: 'Purchased Pro plan', time: '2 min ago' },\n { user: 'Marcus Rivera', action: 'Submitted support ticket', time: '15 min ago' },\n { user: 'Aisha Patel', action: 'Updated profile settings', time: '1 hour ago' },\n { user: 'Tom Weber', action: 'Exported analytics report', time: '2 hours ago' },\n { user: 'Lisa Kim', action: 'Added team member', time: '3 hours ago' }\n ];\n</script>\n\n<SidebarLayout bind:open={sidebarOpen} sidebarWidth=\"14rem\" data-design-pattern=\"dashboard\">\n {#snippet sidebarHeader()}\n <a href=\"/\" class=\"flex h-14 items-center px-4 font-bold text-primary\">Acme Inc</a>\n {/snippet}\n\n {#snippet sidebar()}\n <nav class=\"flex flex-col gap-1 p-3\">\n {#each navItems as item (item.id)}\n {@const Icon = item.icon}\n <button\n type=\"button\"\n onclick={() => (activeRoute = item.id)}\n class={activeRoute === item.id\n ? 'flex items-center gap-2.5 rounded-lg bg-primary-subtle px-3 py-2 text-sm font-medium text-primary'\n : 'flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary'}\n >\n <Icon class=\"h-4 w-4 shrink-0\" />\n <span>{item.label}</span>\n </button>\n {/each}\n </nav>\n {/snippet}\n\n {#snippet sidebarFooter()}\n <div class=\"flex items-center gap-3 p-3\">\n <Avatar name=\"Mara Cohen\" size=\"sm\" />\n <div class=\"min-w-0\">\n <div class=\"truncate text-xs font-medium text-text-primary\">Mara C</div>\n <div class=\"truncate text-[10px] text-text-tertiary\">Admin</div>\n </div>\n </div>\n {/snippet}\n\n {#snippet mobileHeader({ openSidebar })}\n <Button variant=\"ghost\" size=\"sm\" onclick={openSidebar} aria-label=\"Open menu\">\n <MenuIcon class=\"h-5 w-5\" />\n </Button>\n <span class=\"font-semibold\">Acme Inc</span>\n {/snippet}\n\n <div class=\"space-y-6\">\n <div class=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h1 class=\"text-2xl font-bold text-text-primary\">Dashboard</h1>\n <p class=\"text-sm text-text-tertiary\">Welcome back, Mara</p>\n </div>\n <Button size=\"sm\" intent=\"primary\">Export Report</Button>\n </div>\n\n <div class=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n {#each stats as stat (stat.label)}\n <Card class=\"h-full\" variant=\"elevated\">\n <Tooltip label={stat.tooltip} placement=\"top\">\n <div class=\"flex flex-col gap-2\">\n <p class=\"min-h-8 text-xs font-medium text-text-tertiary\">{stat.label}</p>\n <div class=\"flex items-baseline gap-2\">\n <span class=\"text-2xl font-bold tabular-nums text-text-primary\">{stat.value}</span>\n <Badge variant=\"soft\" intent={stat.intent} size=\"sm\">{stat.change}</Badge>\n </div>\n <Progress\n value={stat.progress}\n size=\"xs\"\n intent={stat.intent === 'danger' ? 'danger' : 'primary'}\n />\n </div>\n </Tooltip>\n </Card>\n {/each}\n </div>\n\n <Card>\n <div class=\"space-y-4\">\n <h3 class=\"text-sm font-semibold text-text-primary\">Revenue Overview</h3>\n <div class=\"flex h-48 items-end gap-2\">\n {#each chartData as height, i (i)}\n <div\n class=\"flex-1 rounded-t transition-all duration-(--blocks-duration-fast) hover:opacity-80\"\n style=\"height: {height}%; background: {i === chartData.length - 1\n ? 'var(--color-primary)'\n : 'var(--color-primary-subtle)'}\"\n ></div>\n {/each}\n </div>\n <div class=\"flex justify-between gap-1 text-[10px] text-text-quaternary\">\n {#each months as month (month)}\n <span>{month}</span>\n {/each}\n </div>\n </div>\n </Card>\n\n <Card>\n <div class=\"space-y-4\">\n <h3 class=\"text-sm font-semibold text-text-primary\">Recent Activity</h3>\n <div class=\"space-y-3\">\n {#each recentActivity as activity (activity.user)}\n <div class=\"flex items-start gap-3\">\n <Avatar name={activity.user} size=\"sm\" />\n <div class=\"min-w-0 flex-1\">\n <p class=\"truncate text-sm font-medium text-text-primary\">{activity.user}</p>\n <p class=\"text-xs text-text-tertiary\">{activity.action} · {activity.time}</p>\n </div>\n </div>\n {/each}\n </div>\n </div>\n </Card>\n </div>\n</SidebarLayout>",
4531
+ "code": "<script lang=\"ts\">\n import {\n Avatar, Badge, BarChart, Button, Card, Progress, Tooltip,\n SidebarLayout, MenuIcon, HomeIcon, BarChartIcon, UsersIcon, SettingsIcon\n } from '@urbicon-ui/blocks';\n\n let sidebarOpen = $state(false);\n let activeRoute = $state('dashboard');\n\n const navItems = [\n { id: 'dashboard', label: 'Dashboard', icon: HomeIcon },\n { id: 'analytics', label: 'Analytics', icon: BarChartIcon },\n { id: 'users', label: 'Users', icon: UsersIcon },\n { id: 'settings', label: 'Settings', icon: SettingsIcon }\n ];\n\n const stats = [\n { label: 'Total Users', value: '12,847', change: '+12.5%', intent: 'success' as const, progress: 78, tooltip: 'Target: 16,500 users by Q2' },\n { label: 'Revenue', value: '$48,392', change: '+8.2%', intent: 'success' as const, progress: 64, tooltip: 'Target: $75,000 monthly' },\n { label: 'Active Sessions', value: '1,429', change: '-3.1%', intent: 'danger' as const, progress: 45, tooltip: 'Down from 1,475 last week' },\n { label: 'Conversion', value: '3.24%', change: '+0.8%', intent: 'success' as const, progress: 81, tooltip: 'Target: 4.0% conversion rate' }\n ];\n\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const chartData = [40, 65, 45, 80, 55, 70, 85, 60, 90, 75, 95, 88];\n const revenue = months.map((label, i) => ({ label, values: [chartData[i]] }));\n\n const recentActivity = [\n { user: 'Sarah Chen', action: 'Purchased Pro plan', time: '2 min ago' },\n { user: 'Marcus Rivera', action: 'Submitted support ticket', time: '15 min ago' },\n { user: 'Aisha Patel', action: 'Updated profile settings', time: '1 hour ago' },\n { user: 'Tom Weber', action: 'Exported analytics report', time: '2 hours ago' },\n { user: 'Lisa Kim', action: 'Added team member', time: '3 hours ago' }\n ];\n</script>\n\n<SidebarLayout bind:open={sidebarOpen} sidebarWidth=\"14rem\" data-design-pattern=\"dashboard\">\n {#snippet sidebarHeader()}\n <a href=\"/\" class=\"flex h-14 items-center px-4 font-bold text-primary\">Acme Inc</a>\n {/snippet}\n\n {#snippet sidebar()}\n <nav class=\"flex flex-col gap-1 p-3\">\n {#each navItems as item (item.id)}\n {@const Icon = item.icon}\n <button\n type=\"button\"\n onclick={() => (activeRoute = item.id)}\n class={activeRoute === item.id\n ? 'flex items-center gap-2.5 rounded-lg bg-primary-subtle px-3 py-2 text-sm font-medium text-primary'\n : 'flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary'}\n >\n <Icon class=\"h-4 w-4 shrink-0\" />\n <span>{item.label}</span>\n </button>\n {/each}\n </nav>\n {/snippet}\n\n {#snippet sidebarFooter()}\n <div class=\"flex items-center gap-3 p-3\">\n <Avatar name=\"Mara Cohen\" size=\"sm\" />\n <div class=\"min-w-0\">\n <div class=\"truncate text-xs font-medium text-text-primary\">Mara C</div>\n <div class=\"truncate text-[10px] text-text-tertiary\">Admin</div>\n </div>\n </div>\n {/snippet}\n\n {#snippet mobileHeader({ openSidebar })}\n <Button variant=\"ghost\" size=\"sm\" onclick={openSidebar} aria-label=\"Open menu\">\n <MenuIcon class=\"h-5 w-5\" />\n </Button>\n <span class=\"font-semibold\">Acme Inc</span>\n {/snippet}\n\n <div class=\"space-y-6\">\n <div class=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h1 class=\"text-2xl font-bold text-text-primary\">Dashboard</h1>\n <p class=\"text-sm text-text-tertiary\">Welcome back, Mara</p>\n </div>\n <Button size=\"sm\" intent=\"primary\">Export Report</Button>\n </div>\n\n <div class=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n {#each stats as stat (stat.label)}\n <Card class=\"h-full\" variant=\"elevated\">\n <Tooltip label={stat.tooltip} placement=\"top\">\n <div class=\"flex flex-col gap-2\">\n <p class=\"min-h-8 text-xs font-medium text-text-tertiary\">{stat.label}</p>\n <div class=\"flex items-baseline gap-2\">\n <span class=\"text-2xl font-bold tabular-nums text-text-primary\">{stat.value}</span>\n <Badge variant=\"soft\" intent={stat.intent} size=\"sm\">{stat.change}</Badge>\n </div>\n <Progress\n value={stat.progress}\n size=\"xs\"\n intent={stat.intent === 'danger' ? 'danger' : 'primary'}\n />\n </div>\n </Tooltip>\n </Card>\n {/each}\n </div>\n\n <Card>\n <div class=\"space-y-4\">\n <h2 class=\"text-sm font-semibold text-text-primary\">Revenue Overview</h2>\n <BarChart\n data={revenue}\n series={[{ label: 'Revenue' }]}\n height={192}\n showLegend={false}\n ariaLabel=\"Monthly revenue\"\n />\n </div>\n </Card>\n\n <Card>\n <div class=\"space-y-4\">\n <h2 class=\"text-sm font-semibold text-text-primary\">Recent Activity</h2>\n <div class=\"space-y-3\">\n {#each recentActivity as activity (activity.user)}\n <div class=\"flex items-start gap-3\">\n <Avatar name={activity.user} size=\"sm\" />\n <div class=\"min-w-0 flex-1\">\n <p class=\"truncate text-sm font-medium text-text-primary\">{activity.user}</p>\n <p class=\"text-xs text-text-tertiary\">{activity.action} · {activity.time}</p>\n </div>\n </div>\n {/each}\n </div>\n </div>\n </Card>\n </div>\n</SidebarLayout>",
4485
4532
  "features": [
4486
4533
  "SidebarLayout as the app shell — responsive sidebar with mobile hamburger overlay",
4487
4534
  "Stat cards with equal height and baseline-aligned values",
@@ -4504,7 +4551,7 @@
4504
4551
  "Alert",
4505
4552
  "Separator"
4506
4553
  ],
4507
- "code": "<script lang=\"ts\">\n import { Button, Input, Checkbox, Card, Alert } from '@urbicon-ui/blocks';\n\n let email = $state('');\n let password = $state('');\n let rememberMe = $state(false);\n let loading = $state(false);\n let error = $state('');\n\n let emailValid = $derived(\n email === '' || /^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$/.test(email)\n );\n let canSubmit = $derived(email !== '' && password.length >= 8 && emailValid);\n\n async function handleLogin() {\n if (!canSubmit) return;\n loading = true;\n error = '';\n await new Promise((r) => setTimeout(r, 1500));\n // Replace with your auth logic\n if (email === 'demo@example.com' && password === 'password123') {\n window.location.href = '/dashboard';\n } else {\n error = 'Invalid credentials';\n }\n loading = false;\n }\n</script>\n\n<Card class=\"mx-auto max-w-sm shadow-lg\">\n <div class=\"p-8\">\n <h3 class=\"mb-6 text-center text-xl font-bold\">Sign In</h3>\n\n {#if error}\n <Alert intent=\"danger\" variant=\"soft\" size=\"sm\" dismissible\n onDismiss={() => (error = '')}>{error}</Alert>\n {/if}\n\n <form onsubmit={(e) => { e.preventDefault(); handleLogin(); }}>\n <Input label=\"Email\" type=\"email\" placeholder=\"you@example.com\"\n bind:value={email}\n error={!emailValid ? 'Invalid email' : undefined} />\n\n <Input label=\"Password\" type=\"password\"\n bind:value={password} class=\"mt-4\" />\n\n <div class=\"mt-4 flex items-center justify-between\">\n <Checkbox label=\"Remember me\" bind:checked={rememberMe} />\n <a href=\"/forgot\" class=\"text-sm text-primary\">Forgot?</a>\n </div>\n\n <Button intent=\"primary\" class=\"mt-6 w-full\"\n disabled={!canSubmit} {loading}>\n Sign in\n </Button>\n </form>\n </div>\n</Card>",
4554
+ "code": "<script lang=\"ts\">\n import { Button, Input, Checkbox, Card, Alert } from '@urbicon-ui/blocks';\n\n let email = $state('');\n let password = $state('');\n let rememberMe = $state(false);\n let loading = $state(false);\n let error = $state('');\n\n let emailValid = $derived(\n email === '' || /^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$/.test(email)\n );\n let canSubmit = $derived(email !== '' && password.length >= 8 && emailValid);\n\n async function handleLogin() {\n if (!canSubmit) return;\n loading = true;\n error = '';\n await new Promise((r) => setTimeout(r, 1500));\n // Replace with your auth logic\n if (email === 'demo@example.com' && password === 'password123') {\n window.location.href = '/dashboard';\n } else {\n error = 'Invalid credentials';\n }\n loading = false;\n }\n</script>\n\n<Card class=\"mx-auto max-w-sm shadow-lg\">\n <div class=\"p-8\">\n <h3 class=\"mb-6 text-center text-xl font-bold\">Sign In</h3>\n\n {#if error}\n <Alert intent=\"danger\" variant=\"soft\" size=\"sm\" dismissible\n onDismiss={() => (error = '')}>{error}</Alert>\n {/if}\n\n <form onsubmit={(e) => { e.preventDefault(); handleLogin(); }}>\n <Input label=\"Email\" type=\"email\" placeholder=\"you@example.com\"\n bind:value={email}\n error={!emailValid ? 'Invalid email' : undefined} />\n\n <Input label=\"Password\" type=\"password\"\n bind:value={password} class=\"mt-4\" />\n\n <div class=\"mt-4 flex items-center justify-between\">\n <Checkbox label=\"Remember me\" bind:checked={rememberMe} />\n <a href=\"/forgot\" class=\"text-sm text-primary\">Forgot?</a>\n </div>\n\n <Button intent=\"primary\" class=\"mt-6 w-full\" type=\"submit\"\n disabled={loading} {loading}>\n Sign in\n </Button>\n </form>\n </div>\n</Card>",
4508
4555
  "features": [
4509
4556
  "Client-side email and password validation",
4510
4557
  "Show/hide password toggle",
package/content/meta.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "6.3.1",
3
- "builtAt": "2026-06-23T14:32:43.841Z",
4
- "contentHash": "143f34e6e5f9"
2
+ "version": "6.3.3",
3
+ "builtAt": "2026-06-24T07:50:05.652Z",
4
+ "contentHash": "180ad3c87448"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@urbicon-ui/design-content",
3
- "version": "6.3.1",
3
+ "version": "6.3.3",
4
4
  "description": "Version-pinned bundle of Urbicon UI design knowledge — component catalog, per-component llm.txt, design-system principles + patterns, guide template and icon metadata — plus a package-relative locator. Consumed by the remote MCP server and the urbicon CLI.",
5
5
  "license": "MIT",
6
6
  "repository": {