@elytracms/studio 0.0.76 → 0.0.78
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/convex/cms.ts +11 -107
- package/convex/contract-parity.test.ts +238 -0
- package/convex/schema.ts +6 -5
- package/convex/tsconfig.json +3 -1
- package/dist/components/cms/collection-table.js +1 -1
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/doc-state.d.ts +3 -2
- package/dist/components/cms/doc-state.js +3 -2
- package/dist/components/cms/doc-state.js.map +1 -1
- package/dist/lib/auth/route-guard.d.ts +24 -3
- package/dist/lib/auth/route-guard.js +25 -4
- package/dist/lib/auth/route-guard.js.map +1 -1
- package/dist/lib/persistence/convex-adapter.js +3 -3
- package/dist/lib/persistence/convex-adapter.js.map +1 -1
- package/dist/router/root.js +13 -3
- package/dist/router/root.js.map +1 -1
- package/dist/ui/status-dot.d.ts +11 -8
- package/dist/ui/status-dot.js +7 -5
- package/dist/ui/status-dot.js.map +1 -1
- package/package.json +3 -2
package/dist/ui/status-dot.d.ts
CHANGED
|
@@ -18,8 +18,9 @@ export interface StatusDotProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'c
|
|
|
18
18
|
tone: StatusTone;
|
|
19
19
|
/**
|
|
20
20
|
* The accessible + hover/focus-revealed text (e.g. "Published"). Exposed as the
|
|
21
|
-
* `aria-label`
|
|
22
|
-
* keyboard user
|
|
21
|
+
* `aria-label` (screen readers) and shown as a small pill on hover/focus so a
|
|
22
|
+
* mouse OR keyboard user can read it — no native `title` (EC-452: it duplicated
|
|
23
|
+
* the pill, showing the label twice on mouse hover).
|
|
23
24
|
*/
|
|
24
25
|
label: string;
|
|
25
26
|
/**
|
|
@@ -27,8 +28,8 @@ export interface StatusDotProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'c
|
|
|
27
28
|
* EC-446 focusable behavior (the versions pane — a few rows — so a keyboard user can
|
|
28
29
|
* focus a dot to reveal its pill). Pass `false` for a DENSE surface (the list
|
|
29
30
|
* `$state` column, EC-448): a long list must not add a tab stop per row. The label
|
|
30
|
-
* stays reachable via `aria-label`
|
|
31
|
-
*
|
|
31
|
+
* stays reachable via `aria-label` (and the hover pill on mouse) — just not via
|
|
32
|
+
* focus. The focus-ring styling is likewise dropped when non-interactive.
|
|
32
33
|
*/
|
|
33
34
|
interactive?: boolean;
|
|
34
35
|
}
|
|
@@ -39,10 +40,12 @@ export interface StatusDotProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'c
|
|
|
39
40
|
* list `$state` column). Pure-presentational and domain-agnostic: it knows a
|
|
40
41
|
* `tone` and a `label`, nothing about versions or documents.
|
|
41
42
|
*
|
|
42
|
-
* Accessibility: the wrapper is `role="img"` and carries the label as
|
|
43
|
-
* `aria-label` (screen readers)
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* Accessibility: the wrapper is `role="img"` and carries the label as its
|
|
44
|
+
* `aria-label` (screen readers) — no native `title` (EC-452: pairing one with
|
|
45
|
+
* the CSS pill below made the label show twice on mouse hover; the pill is the
|
|
46
|
+
* one hover surface now). When `interactive` (the default), it is also
|
|
47
|
+
* focusable (`tabIndex=0`) and the same CSS pill reveals the label on
|
|
48
|
+
* `:focus-visible`, so the meaning is reachable without a mouse; a
|
|
46
49
|
* non-interactive dot (EC-448, dense lists) drops the tab stop + focus ring but
|
|
47
50
|
* keeps the name + hover pill. The dot glyph and the pill are `aria-hidden` — the
|
|
48
51
|
* wrapper's `aria-label` is the single announced name.
|
package/dist/ui/status-dot.js
CHANGED
|
@@ -24,15 +24,17 @@ export function statusDotToneClass(tone) {
|
|
|
24
24
|
* list `$state` column). Pure-presentational and domain-agnostic: it knows a
|
|
25
25
|
* `tone` and a `label`, nothing about versions or documents.
|
|
26
26
|
*
|
|
27
|
-
* Accessibility: the wrapper is `role="img"` and carries the label as
|
|
28
|
-
* `aria-label` (screen readers)
|
|
29
|
-
*
|
|
30
|
-
*
|
|
27
|
+
* Accessibility: the wrapper is `role="img"` and carries the label as its
|
|
28
|
+
* `aria-label` (screen readers) — no native `title` (EC-452: pairing one with
|
|
29
|
+
* the CSS pill below made the label show twice on mouse hover; the pill is the
|
|
30
|
+
* one hover surface now). When `interactive` (the default), it is also
|
|
31
|
+
* focusable (`tabIndex=0`) and the same CSS pill reveals the label on
|
|
32
|
+
* `:focus-visible`, so the meaning is reachable without a mouse; a
|
|
31
33
|
* non-interactive dot (EC-448, dense lists) drops the tab stop + focus ring but
|
|
32
34
|
* keeps the name + hover pill. The dot glyph and the pill are `aria-hidden` — the
|
|
33
35
|
* wrapper's `aria-label` is the single announced name.
|
|
34
36
|
*/
|
|
35
37
|
export function StatusDot({ tone, label, className, interactive = true, ...props }) {
|
|
36
|
-
return (_jsxs("span", { role: "img", ...(interactive ? { tabIndex: 0 } : {}), "aria-label": label,
|
|
38
|
+
return (_jsxs("span", { role: "img", ...(interactive ? { tabIndex: 0 } : {}), "aria-label": label, className: cn('group/status-dot relative inline-flex items-center justify-center rounded-full outline-none', interactive && 'focus-visible:ring-2 focus-visible:ring-ring/60', className), ...props, children: [_jsx("span", { "aria-hidden": true, className: cn('size-2 shrink-0 rounded-full', statusDotToneClass(tone)) }), _jsx("span", { "aria-hidden": true, className: cn('pointer-events-none absolute left-1/2 top-full z-50 mt-1.5 -translate-x-1/2 whitespace-nowrap', 'rounded-md border border-border bg-popover px-2 py-1 text-xs font-medium text-popover-foreground shadow-md', 'opacity-0 transition-opacity duration-100', 'group-hover/status-dot:opacity-100 group-focus-visible/status-dot:opacity-100'), children: label })] }));
|
|
37
39
|
}
|
|
38
40
|
//# sourceMappingURL=status-dot.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-dot.js","sourceRoot":"","sources":["../../src/ui/status-dot.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAWjC;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAgB;IACjD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,YAAY,CAAA;QACrB,KAAK,SAAS;YACZ,OAAO,YAAY,CAAA;QACrB,KAAK,OAAO;YACV,OAAO,wBAAwB,CAAA;QACjC,KAAK,SAAS;YACZ,OAAO,qBAAqB,CAAA;IAChC,CAAC;AACH,CAAC;
|
|
1
|
+
{"version":3,"file":"status-dot.js","sourceRoot":"","sources":["../../src/ui/status-dot.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAWjC;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAgB;IACjD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,YAAY,CAAA;QACrB,KAAK,SAAS;YACZ,OAAO,YAAY,CAAA;QACrB,KAAK,OAAO;YACV,OAAO,wBAAwB,CAAA;QACjC,KAAK,SAAS;YACZ,OAAO,qBAAqB,CAAA;IAChC,CAAC;AACH,CAAC;AAuBD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,GAAG,IAAI,EAAE,GAAG,KAAK,EAAkB;IAChG,OAAO,CACL,gBACE,IAAI,EAAC,KAAK,KACN,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,gBAC5B,KAAK,EACjB,SAAS,EAAE,EAAE,CACX,6FAA6F,EAC7F,WAAW,IAAI,iDAAiD,EAChE,SAAS,CACV,KACG,KAAK,aAET,oCAAkB,SAAS,EAAE,EAAE,CAAC,8BAA8B,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC,GAAI,EAC7F,oCAEE,SAAS,EAAE,EAAE,CACX,+FAA+F,EAC/F,4GAA4G,EAC5G,2CAA2C,EAC3C,+EAA+E,CAChF,YAEA,KAAK,GACD,IACF,CACR,CAAA;AACH,CAAC","sourcesContent":["import type { HTMLAttributes } from 'react'\nimport { cn } from '../lib/utils'\n\n/**\n * The status vocabulary a {@link StatusDot} can express. Kept deliberately\n * generic (not domain-specific) so the same primitive marks a published version\n * (`success`), a draft/pending state (`warning`), or a quiet/absent state\n * (`muted`/`neutral`) — the versions pane (EC-446) is its first consumer, the\n * list `$state` column (EC-445) its next.\n */\nexport type StatusTone = 'success' | 'warning' | 'muted' | 'neutral'\n\n/**\n * The dot's fill class per tone — a pure mapping onto the shared token palette\n * (the same `--success`/`--warning`/`--muted-foreground` tokens {@link Badge}\n * uses), extracted so it is unit-testable without a DOM.\n */\nexport function statusDotToneClass(tone: StatusTone): string {\n switch (tone) {\n case 'success':\n return 'bg-success'\n case 'warning':\n return 'bg-warning'\n case 'muted':\n return 'bg-muted-foreground/40'\n case 'neutral':\n return 'bg-muted-foreground'\n }\n}\n\nexport interface StatusDotProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'children' | 'aria-label'> {\n /** Which status the dot expresses — maps onto the shared token palette. */\n tone: StatusTone\n /**\n * The accessible + hover/focus-revealed text (e.g. \"Published\"). Exposed as the\n * `aria-label` (screen readers) and shown as a small pill on hover/focus so a\n * mouse OR keyboard user can read it — no native `title` (EC-452: it duplicated\n * the pill, showing the label twice on mouse hover).\n */\n label: string\n /**\n * Whether the dot is a keyboard tab stop (EC-448). **Default `true`** preserves the\n * EC-446 focusable behavior (the versions pane — a few rows — so a keyboard user can\n * focus a dot to reveal its pill). Pass `false` for a DENSE surface (the list\n * `$state` column, EC-448): a long list must not add a tab stop per row. The label\n * stays reachable via `aria-label` (and the hover pill on mouse) — just not via\n * focus. The focus-ring styling is likewise dropped when non-interactive.\n */\n interactive?: boolean\n}\n\n/**\n * EC-446 — a compact, reusable status indicator: a small colored dot whose\n * meaning is revealed on hover/focus rather than spent as a full-width pill. The\n * primary space win over {@link Badge} for dense rows (the versions history, the\n * list `$state` column). Pure-presentational and domain-agnostic: it knows a\n * `tone` and a `label`, nothing about versions or documents.\n *\n * Accessibility: the wrapper is `role=\"img\"` and carries the label as its\n * `aria-label` (screen readers) — no native `title` (EC-452: pairing one with\n * the CSS pill below made the label show twice on mouse hover; the pill is the\n * one hover surface now). When `interactive` (the default), it is also\n * focusable (`tabIndex=0`) and the same CSS pill reveals the label on\n * `:focus-visible`, so the meaning is reachable without a mouse; a\n * non-interactive dot (EC-448, dense lists) drops the tab stop + focus ring but\n * keeps the name + hover pill. The dot glyph and the pill are `aria-hidden` — the\n * wrapper's `aria-label` is the single announced name.\n */\nexport function StatusDot({ tone, label, className, interactive = true, ...props }: StatusDotProps) {\n return (\n <span\n role=\"img\"\n {...(interactive ? { tabIndex: 0 } : {})}\n aria-label={label}\n className={cn(\n 'group/status-dot relative inline-flex items-center justify-center rounded-full outline-none',\n interactive && 'focus-visible:ring-2 focus-visible:ring-ring/60',\n className,\n )}\n {...props}\n >\n <span aria-hidden className={cn('size-2 shrink-0 rounded-full', statusDotToneClass(tone))} />\n <span\n aria-hidden\n className={cn(\n 'pointer-events-none absolute left-1/2 top-full z-50 mt-1.5 -translate-x-1/2 whitespace-nowrap',\n 'rounded-md border border-border bg-popover px-2 py-1 text-xs font-medium text-popover-foreground shadow-md',\n 'opacity-0 transition-opacity duration-100',\n 'group-hover/status-dot:opacity-100 group-focus-visible/status-dot:opacity-100',\n )}\n >\n {label}\n </span>\n </span>\n )\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elytracms/studio",
|
|
3
3
|
"author": "finaldream <hi@finaldream.de>",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.78",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "The Elytra studio engine (UI + lib + routes + data-only Convex schema) as an importable package. Extraction staged in EXTRACTION.md (EC-223); Stages 1-2 = UI primitives + router-free lib leaves.",
|
|
7
7
|
"license": "MIT",
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
"lucide-react": "^1.23.0",
|
|
151
151
|
"tailwind-merge": "^3.6.0",
|
|
152
152
|
"zod": "^4.4.3",
|
|
153
|
-
"@elytracms/core": "^0.0.
|
|
153
|
+
"@elytracms/core": "^0.0.78"
|
|
154
154
|
},
|
|
155
155
|
"peerDependencies": {
|
|
156
156
|
"@tanstack/react-router": "^1.170.0",
|
|
@@ -169,6 +169,7 @@
|
|
|
169
169
|
"@types/node": "^26.1.0",
|
|
170
170
|
"@types/react": "^19.2.17",
|
|
171
171
|
"@types/react-dom": "^19.2.3",
|
|
172
|
+
"convex-test": "^0.0.54",
|
|
172
173
|
"react": "^19.2.7",
|
|
173
174
|
"react-dom": "^19.2.7",
|
|
174
175
|
"typescript": "^6.0.3",
|