@petrarca/sonnet-playground 0.8.0 → 0.9.0
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/README.md +10 -8
- package/dist/{PlayAdvancedComponents-ZYK66UII.js → PlayAdvancedComponents-VMUI472R.js} +2 -2
- package/dist/PlayCodeEditor-AMTFE5SW.js +8 -0
- package/dist/PlayCodedValues-G2EVIVMO.js +9 -0
- package/dist/{PlayCoreComponents-YTEAS3GL.js → PlayCoreComponents-EQ2BMY2S.js} +2 -2
- package/dist/{PlayDataComponents-W44OITT5.js → PlayDataComponents-W2KQHOI7.js} +2 -2
- package/dist/PlayFhirQuestionnaire-TO35Q7CP.js +8 -0
- package/dist/{PlayFormWidgets-6JYFRTAL.js → PlayFormWidgets-HP3VF2LK.js} +2 -2
- package/dist/PlayForms-4CQNEBLS.js +7 -0
- package/dist/PlayGraph-25ZKQAQR.js +7 -0
- package/dist/PlayGraph-25ZKQAQR.js.map +1 -0
- package/dist/PlayMarkdownViewer-X6AIFO2U.js +8 -0
- package/dist/PlayMarkdownViewer-X6AIFO2U.js.map +1 -0
- package/dist/PlayQuestionnaireDesigner-IR7TKSOT.js +9 -0
- package/dist/PlayQuestionnaireDesigner-IR7TKSOT.js.map +1 -0
- package/dist/PlaySchemaDesigner-ZQBA7AYO.js +8 -0
- package/dist/PlaySchemaDesigner-ZQBA7AYO.js.map +1 -0
- package/dist/{PlayShellApi-5O6VYR2X.js → PlayShellApi-MMCQ2AKK.js} +2 -2
- package/dist/PlayShellApi-MMCQ2AKK.js.map +1 -0
- package/dist/chunk-3FYM6B3E.js +1163 -0
- package/dist/chunk-3FYM6B3E.js.map +1 -0
- package/dist/{chunk-CQ6PGFRV.js → chunk-3RZHYZRL.js} +57 -1
- package/dist/chunk-3RZHYZRL.js.map +1 -0
- package/dist/chunk-7IMCPUSI.js +100 -0
- package/dist/chunk-7IMCPUSI.js.map +1 -0
- package/dist/{chunk-2XMWOZ5O.js → chunk-EPCUUTBZ.js} +48 -41
- package/dist/chunk-EPCUUTBZ.js.map +1 -0
- package/dist/{chunk-BRH3FFFT.js → chunk-LDCNLHO2.js} +15 -1
- package/dist/chunk-LDCNLHO2.js.map +1 -0
- package/dist/chunk-LVV32F7G.js +104 -0
- package/dist/chunk-LVV32F7G.js.map +1 -0
- package/dist/chunk-OUL3DN2E.js +510 -0
- package/dist/chunk-OUL3DN2E.js.map +1 -0
- package/dist/chunk-QKFQI4VX.js +83 -0
- package/dist/chunk-QKFQI4VX.js.map +1 -0
- package/dist/{chunk-6WI3N7JI.js → chunk-RGBSHXS5.js} +145 -4
- package/dist/chunk-RGBSHXS5.js.map +1 -0
- package/dist/{chunk-UB7462QG.js → chunk-RLJI5VMP.js} +72 -1
- package/dist/chunk-RLJI5VMP.js.map +1 -0
- package/dist/chunk-VGAS5Z6X.js +543 -0
- package/dist/chunk-VGAS5Z6X.js.map +1 -0
- package/dist/chunk-VKZ2RJFL.js +647 -0
- package/dist/chunk-VKZ2RJFL.js.map +1 -0
- package/dist/chunk-WR74TMW4.js +219 -0
- package/dist/chunk-WR74TMW4.js.map +1 -0
- package/dist/{chunk-E5X7GVLU.js → chunk-XNDD4UN4.js} +2 -2
- package/dist/chunk-XNDD4UN4.js.map +1 -0
- package/dist/chunk-YTGQRDD2.js +343 -0
- package/dist/chunk-YTGQRDD2.js.map +1 -0
- package/dist/index.d.ts +13 -10
- package/dist/index.js +72 -11
- package/dist/index.js.map +1 -1
- package/dist/pages/index.d.ts +56 -20
- package/dist/pages/index.js +39 -17
- package/package.json +15 -14
- package/dist/PlayForms-U2TWUX5L.js +0 -7
- package/dist/PlayGraph-M4KQSFI7.js +0 -7
- package/dist/PlaySchemaDesigner-S4DBB53G.js +0 -7
- package/dist/chunk-2XMWOZ5O.js.map +0 -1
- package/dist/chunk-4Y4JFKAK.js +0 -240
- package/dist/chunk-4Y4JFKAK.js.map +0 -1
- package/dist/chunk-6WI3N7JI.js.map +0 -1
- package/dist/chunk-BRH3FFFT.js.map +0 -1
- package/dist/chunk-CQ6PGFRV.js.map +0 -1
- package/dist/chunk-E5X7GVLU.js.map +0 -1
- package/dist/chunk-O2QMWJZI.js +0 -881
- package/dist/chunk-O2QMWJZI.js.map +0 -1
- package/dist/chunk-UB7462QG.js.map +0 -1
- /package/dist/{PlayAdvancedComponents-ZYK66UII.js.map → PlayAdvancedComponents-VMUI472R.js.map} +0 -0
- /package/dist/{PlayCoreComponents-YTEAS3GL.js.map → PlayCodeEditor-AMTFE5SW.js.map} +0 -0
- /package/dist/{PlayDataComponents-W44OITT5.js.map → PlayCodedValues-G2EVIVMO.js.map} +0 -0
- /package/dist/{PlayFormWidgets-6JYFRTAL.js.map → PlayCoreComponents-EQ2BMY2S.js.map} +0 -0
- /package/dist/{PlayForms-U2TWUX5L.js.map → PlayDataComponents-W2KQHOI7.js.map} +0 -0
- /package/dist/{PlayGraph-M4KQSFI7.js.map → PlayFhirQuestionnaire-TO35Q7CP.js.map} +0 -0
- /package/dist/{PlaySchemaDesigner-S4DBB53G.js.map → PlayFormWidgets-HP3VF2LK.js.map} +0 -0
- /package/dist/{PlayShellApi-5O6VYR2X.js.map → PlayForms-4CQNEBLS.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pages/PlayDataComponents.tsx","../src/pages/EntityTableLongListDemo.tsx"],"sourcesContent":["/**\n * Playground page for SearchInput, EntitySelect, EntityTable, and EntityTree.\n * Accessible at /playground/data-components\n *\n * Six sections:\n * 1. Simple mode -- single freetext search, no field picker\n * 2. Faceted mode -- two-column: schema editor left, live search + output right\n * 3. EntityTable -- static sample data wired to faceted SearchInput\n * 4. Local renderers -- same data with x- prefixed custom cell renderers\n * 5. EntitySelect -- async searchable select backed by a static mock fetcher\n * 6. EntityTree -- schema-driven tree with static nested data\n */\n\nimport React, { useState, useMemo, useCallback } from \"react\";\nimport { ArrowRight, ArrowUp } from \"lucide-react\";\nimport {\n Badge,\n Button,\n Card,\n SimpleTooltip,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n SearchInput,\n type SearchMode,\n EntitySelect,\n EntityTable,\n createRenderer,\n EntityTree,\n PropertyList,\n type TreeNode,\n type TableUiSchema,\n type SortingState,\n type TableDensity,\n} from \"@petrarca/sonnet-ui\";\nimport type { JsonSchemaProperty } from \"@petrarca/sonnet-core/schema\";\nimport { FormTextarea } from \"@petrarca/sonnet-forms\";\nimport { JsonEditor } from \"@petrarca/sonnet-ui/json-editor\";\nimport { PlaygroundSection } from \"../PlaygroundSection\";\nimport { EntityTableLongListDemo } from \"./EntityTableLongListDemo\";\nimport {\n EMPTY_FILTER,\n flattenFilterExpr,\n isEmptyFilterExpr,\n serializeFilterExpr,\n type FilterExpr,\n} from \"@petrarca/sonnet-core/search\";\nimport { toJsonSchema, type JsonSchema } from \"@petrarca/sonnet-core/schema\";\nimport { useTreeExpansion } from \"@petrarca/sonnet-core/hooks\";\nimport type { EntityOptionFetcher } from \"@petrarca/sonnet-core/entityOptions\";\nimport { z } from \"zod/v4\";\n\n// Static mock patient data for the EntitySelect playground demo.\n// Uses a local fetcher so the playground has no dependency on a live API.\nconst MOCK_PATIENTS = [\n { value: \"pat_001\", label: \"Alice Hartmann\" },\n { value: \"pat_002\", label: \"Bob Nguyen\" },\n { value: \"pat_003\", label: \"Carol Smith\" },\n { value: \"pat_004\", label: \"David Okafor\" },\n { value: \"pat_005\", label: \"Eva Larsson\" },\n { value: \"pat_006\", label: \"Frank Torres\" },\n { value: \"pat_007\", label: \"Grace Kim\" },\n { value: \"pat_008\", label: \"Henry Bauer\" },\n];\n\nconst patientFetcher: EntityOptionFetcher = ({ search } = {}) => {\n const q = search?.toLowerCase() ?? \"\";\n const results = q\n ? MOCK_PATIENTS.filter((p) => p.label.toLowerCase().includes(q))\n : MOCK_PATIENTS;\n return Promise.resolve(results);\n};\n\ninterface SampleRow {\n id: string;\n name: string;\n status: \"active\" | \"inactive\" | \"pending\";\n role: string;\n joined: string;\n}\n\nconst ALL_ROWS: SampleRow[] = [\n {\n id: \"u-001\",\n name: \"Alice Hartmann\",\n status: \"active\",\n role: \"admin\",\n joined: \"2024-01-15\",\n },\n {\n id: \"u-002\",\n name: \"Bob Nguyen\",\n status: \"active\",\n role: \"editor\",\n joined: \"2024-02-03\",\n },\n {\n id: \"u-003\",\n name: \"Carol Smith\",\n status: \"inactive\",\n role: \"viewer\",\n joined: \"2024-03-20\",\n },\n {\n id: \"u-004\",\n name: \"David Okafor\",\n status: \"pending\",\n role: \"editor\",\n joined: \"2024-04-11\",\n },\n {\n id: \"u-005\",\n name: \"Eva Larsson\",\n status: \"active\",\n role: \"admin\",\n joined: \"2024-05-08\",\n },\n {\n id: \"u-006\",\n name: \"Frank Torres\",\n status: \"inactive\",\n role: \"viewer\",\n joined: \"2024-06-22\",\n },\n {\n id: \"u-007\",\n name: \"Grace Kim\",\n status: \"active\",\n role: \"editor\",\n joined: \"2024-07-14\",\n },\n {\n id: \"u-008\",\n name: \"Henry Bauer\",\n status: \"pending\",\n role: \"viewer\",\n joined: \"2024-08-30\",\n },\n];\n\nconst STATUS_COLOR = {\n active: \"green\",\n inactive: \"violet\",\n pending: \"yellow\",\n} as const;\n\nconst PlaygroundFacets = z.object({\n search: z.string().meta({ \"x-ui-title\": \"Name\" }),\n status: z\n .enum([\"active\", \"inactive\", \"pending\"])\n .optional()\n .meta({\n \"x-ui-title\": \"Status\",\n \"x-ui-options\": {\n enumNames: {\n active: \"Active\",\n inactive: \"Inactive\",\n pending: \"Pending\",\n },\n },\n }),\n // An array facet is repeatable: one chip per role, matching any of them.\n roles: z\n .array(z.enum([\"admin\", \"editor\", \"viewer\"]))\n .optional()\n .meta({ \"x-ui-title\": \"Role\" }),\n joined_from: z.string().optional().meta({\n \"x-ui-title\": \"Joined from\",\n \"x-ui-widget\": \"date\",\n }),\n});\n\nconst SEARCH_FACET_SCHEMA = toJsonSchema(PlaygroundFacets);\n\nconst SAMPLE_SCHEMA: JsonSchema = {\n title: \"User\",\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n title: \"Name\",\n \"x-ui-column\": { order: 0, sortable: true },\n \"x-ui-cell\": \"bold\",\n },\n status: {\n type: \"string\",\n title: \"Status\",\n \"x-ui-column\": { order: 1 },\n \"x-ui-cell\": \"badge\",\n \"x-ui-cell-options\": { colors: STATUS_COLOR },\n },\n role: {\n type: \"string\",\n title: \"Role\",\n \"x-ui-column\": { order: 2 },\n \"x-ui-cell\": \"muted\",\n },\n id: {\n type: \"string\",\n title: \"ID\",\n \"x-ui-column\": { order: 3 },\n \"x-ui-cell\": \"code\",\n },\n joined: {\n type: \"string\",\n format: \"date\",\n title: \"Joined\",\n \"x-ui-column\": { order: 4, sortable: true },\n },\n },\n};\n\nconst SAMPLE_UI_SCHEMA: TableUiSchema = {}; // mutable via the live schema editor below\n\n// Local renderer demo: three x- prefixed renderers using the same SampleRow data.\nconst ROLE_ICONS: Record<string, string> = {\n admin: \"A\",\n editor: \"E\",\n viewer: \"V\",\n};\n\nconst CUSTOM_RENDERERS = {\n // Extract initials from the name, display as avatar circle + name.\n \"x-play-initials\": createRenderer<SampleRow>((row) => {\n const initials = row.name\n .split(\" \")\n .map((w) => w[0])\n .join(\"\");\n return (\n <span className=\"inline-flex items-center gap-2\">\n <span className=\"inline-flex items-center justify-center h-7 w-7 rounded-full bg-muted text-xs font-medium shrink-0\">\n {initials}\n </span>\n <span className=\"font-medium\">{row.name}</span>\n </span>\n );\n }),\n\n // Role with a letter prefix read from options.icons.\n \"x-play-role-icon\": createRenderer<SampleRow>((row, options) => {\n const icons = (options.icons as Record<string, string>) ?? {};\n const icon = icons[row.role] ?? \"?\";\n return (\n <span>\n <span className=\"inline-flex items-center justify-center h-5 w-5 rounded bg-muted text-xs font-mono mr-1.5\">\n {icon}\n </span>\n {row.role}\n </span>\n );\n }),\n\n // Compute days since joined, color-coded by threshold from options.\n \"x-play-tenure\": createRenderer<SampleRow>((row, options) => {\n const threshold = (options.recentDays as number) ?? 365;\n const days = Math.floor(\n (Date.now() - new Date(row.joined).getTime()) / 86_400_000,\n );\n const isRecent = days < threshold;\n return (\n <span className={isRecent ? \"text-primary\" : \"text-muted-foreground\"}>\n {days}d\n </span>\n );\n }),\n};\n\nconst CUSTOM_RENDERER_SCHEMA: JsonSchema = {\n title: \"User (custom renderers)\",\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n title: \"Name\",\n \"x-ui-column\": { order: 0 },\n \"x-ui-cell\": \"x-play-initials\",\n },\n role: {\n type: \"string\",\n title: \"Role\",\n \"x-ui-column\": { order: 1 },\n \"x-ui-cell\": \"x-play-role-icon\",\n \"x-ui-cell-options\": { icons: ROLE_ICONS },\n },\n status: {\n type: \"string\",\n title: \"Status\",\n \"x-ui-column\": { order: 2 },\n \"x-ui-cell\": \"badge\",\n \"x-ui-cell-options\": { colors: STATUS_COLOR },\n },\n joined: {\n type: \"string\",\n title: \"Tenure\",\n \"x-ui-column\": { order: 3 },\n \"x-ui-cell\": \"x-play-tenure\",\n \"x-ui-cell-options\": { recentDays: 500 },\n },\n id: {\n type: \"string\",\n title: \"ID\",\n \"x-ui-column\": { order: 4 },\n \"x-ui-cell\": \"code\",\n },\n },\n};\n\n// Sentinel value meaning \"schema was reloaded, next submit resets the counter to 0\".\nconst SUBMIT_COUNT_RESET = -1;\n\n// Presets for the searchFields demo (Section 1b). Uses the same user domain\n// as the rest of the playground (name, role, status).\nconst SEARCH_FIELD_PRESETS: { label: string; fields: string[] }[] = [\n { label: \"name, role\", fields: [\"name\", \"role\"] },\n { label: \"name (single)\", fields: [\"name\"] },\n { label: \"name, role, status\", fields: [\"name\", \"role\", \"status\"] },\n];\n\n// Reusable toggle-button strip for playground controls.\n// Renders a label followed by a set of pill buttons. className applies to\n// the wrapping fragment's implicit container -- callers place it inside a\n// flex row, so use ml-* on the caller side via the containerClassName prop.\nfunction ToggleStrip<T extends string | number>({\n label,\n options,\n value,\n onChange,\n format,\n containerClassName,\n}: {\n label: string;\n options: readonly T[];\n value: T;\n onChange: (v: T) => void;\n format?: (v: T) => string;\n containerClassName?: string;\n}) {\n const fmt = format ?? String;\n return (\n <div className={`flex items-center gap-3 ${containerClassName ?? \"\"}`}>\n <span className=\"text-xs text-muted-foreground\">{label}:</span>\n {options.map((opt) => (\n <button\n key={String(opt)}\n type=\"button\"\n onClick={() => onChange(opt)}\n className={[\n \"px-3 py-1 rounded-full text-xs font-medium transition-colors\",\n value === opt\n ? \"bg-primary text-primary-foreground\"\n : \"bg-muted text-muted-foreground hover:text-foreground\",\n ].join(\" \")}\n >\n {fmt(opt)}\n </button>\n ))}\n </div>\n );\n}\n\nconst DENSITY_OPTIONS = [\n \"default\",\n \"compact\",\n] as const satisfies readonly TableDensity[];\nconst LAYOUT_OPTIONS = [\"flow\", \"fill\"] as const;\n\nconst MODE_OPTIONS = [\"explicit\", \"debounce\"] as const;\nconst MODE_LABELS: Record<string, string> = {\n explicit: \"Explicit (Enter)\",\n debounce: \"Debounce (300 ms)\",\n};\nconst MIN_CHARS_OPTIONS = [0, 1, 2, 3] as const;\nconst FIELD_PRESET_INDICES = SEARCH_FIELD_PRESETS.map(\n (_, i) => i,\n) as readonly number[];\n\nfunction FilterExprInspector({ expr }: { expr: FilterExpr }) {\n return (\n <pre className=\"mt-3 rounded-md bg-muted px-4 py-3 text-xs overflow-auto max-h-40\">\n {JSON.stringify(expr, null, 2)}\n </pre>\n );\n}\n\nfunction FlatTermsInspector({ expr }: { expr: FilterExpr }) {\n const terms = flattenFilterExpr(expr);\n return (\n <pre className=\"mt-3 rounded-md bg-muted px-4 py-3 text-xs overflow-auto max-h-40\">\n {JSON.stringify(terms, null, 2)}\n </pre>\n );\n}\n\n// The filters of a free-text search (textKey): the query is typed, these are\n// picked.\nconst FREE_TEXT_FACETS = toJsonSchema(\n z.object({\n source: z\n .enum([\"billing-api\", \"billing-web\", \"handbook\"])\n .optional()\n .meta({ \"x-ui-title\": \"Source\" }),\n tags: z.array(z.string()).optional().meta({ \"x-ui-title\": \"Tag\" }),\n ranking: z\n .enum([\"rerank\", \"none\"])\n .optional()\n .meta({\n \"x-ui-title\": \"Ranking\",\n \"x-ui-options\": { enumNames: { rerank: \"Rerank\", none: \"No rerank\" } },\n }),\n }),\n);\n\n/** Playground sandbox for SearchInput, EntitySelect, and EntityTable. */\nexport default function PlayDataComponents(): React.ReactElement {\n // Section 1: simple mode\n const [simpleExpr, setSimpleExpr] = useState<FilterExpr>(EMPTY_FILTER);\n const [simpleMode, setSimpleMode] = useState<SearchMode>(\"explicit\");\n const [simpleMinChars, setSimpleMinChars] = useState(0);\n\n // Section 1b: searchFields mode (multi-field OR)\n const [fieldsExpr, setFieldsExpr] = useState<FilterExpr>(EMPTY_FILTER);\n const [fieldsMode, setFieldsMode] = useState<SearchMode>(\"explicit\");\n const [fieldsMinChars, setFieldsMinChars] = useState(0);\n const [fieldsPresetIdx, setFieldsPresetIdx] = useState(0);\n const activeSearchFields = SEARCH_FIELD_PRESETS[fieldsPresetIdx].fields;\n\n // Section 2b: free text with filters (textKey)\n const [freeTextExpr, setFreeTextExpr] = useState<FilterExpr>(EMPTY_FILTER);\n const [freeTextMode, setFreeTextMode] = useState<SearchMode>(\"explicit\");\n\n // Section 2: faceted mode with live schema editor\n const [facetedExpr, setFacetedExpr] = useState<FilterExpr>(EMPTY_FILTER);\n const [facetedSubmitCount, setFacetedSubmitCount] = useState(0);\n const handleFacetedChange = useCallback((expr: FilterExpr) => {\n setFacetedExpr(expr);\n setFacetedSubmitCount((n) => n + 1);\n }, []);\n const [schemaText, setSchemaText] = useState(() =>\n JSON.stringify(toJsonSchema(PlaygroundFacets), null, 2),\n );\n const [schemaError, setSchemaError] = useState(\"\");\n const [activeSchema, setActiveSchema] =\n useState<JsonSchema>(SEARCH_FACET_SCHEMA);\n\n const handleSchemaTextChange = useCallback((value: string) => {\n setSchemaText(value);\n try {\n JSON.parse(value);\n setSchemaError(\"\");\n } catch {\n setSchemaError(\"Invalid JSON\");\n }\n }, []);\n\n const handleLoadSchema = useCallback(() => {\n try {\n const parsed = JSON.parse(schemaText) as JsonSchema;\n setActiveSchema(parsed);\n setFacetedExpr(EMPTY_FILTER);\n setFacetedSubmitCount(SUBMIT_COUNT_RESET);\n setSchemaError(\"\");\n } catch {\n setSchemaError(\"Invalid JSON -- cannot load\");\n }\n }, [schemaText]);\n\n // Section 3: schema + UI schema editors for the table.\n const [tableSchemaText, setTableSchemaText] = useState(() =>\n JSON.stringify(SAMPLE_SCHEMA, null, 2),\n );\n const [tableUiSchemaText, setTableUiSchemaText] = useState(() =>\n JSON.stringify(SAMPLE_UI_SCHEMA, null, 2),\n );\n const [tableSchemaError, setTableSchemaError] = useState(\"\");\n const [activeTableSchema, setActiveTableSchema] =\n useState<JsonSchema>(SAMPLE_SCHEMA);\n const [activeTableUiSchema, setActiveTableUiSchema] =\n useState<TableUiSchema>(SAMPLE_UI_SCHEMA);\n const [tableSchemaTab, setTableSchemaTab] = useState(\"schema\");\n\n const handleTableSchemaTextChange = useCallback((value: string) => {\n setTableSchemaText(value);\n try {\n JSON.parse(value);\n setTableSchemaError(\"\");\n } catch {\n setTableSchemaError(\"Invalid JSON\");\n }\n }, []);\n\n const handleTableUiSchemaTextChange = useCallback((value: string) => {\n setTableUiSchemaText(value);\n try {\n JSON.parse(value);\n setTableSchemaError(\"\");\n } catch {\n setTableSchemaError(\"Invalid JSON\");\n }\n }, []);\n\n const handleApplyTableSchema = useCallback(() => {\n try {\n const schema = JSON.parse(tableSchemaText) as JsonSchema;\n const uiSchema = JSON.parse(tableUiSchemaText) as TableUiSchema;\n setActiveTableSchema(schema);\n setActiveTableUiSchema(uiSchema);\n setTableSchemaError(\"\");\n } catch {\n setTableSchemaError(\"Invalid JSON -- cannot apply\");\n }\n }, [tableSchemaText, tableUiSchemaText]);\n\n // Section 3: faceted mode wired to EntityTable.\n // onChange fires only on submit -- filteredRows updates when the user presses Enter.\n const [tableExpr, setTableExpr] = useState<FilterExpr>(EMPTY_FILTER);\n\n // Sorting is the \"server's\": the table reports it, this query applies it.\n const [tableSorting, setTableSorting] = useState<SortingState>([]);\n const [tableDensity, setTableDensity] = useState<TableDensity>(\"default\");\n const [tableLayout, setTableLayout] =\n useState<(typeof LAYOUT_OPTIONS)[number]>(\"flow\");\n\n const filteredRows = useMemo(() => {\n const terms = flattenFilterExpr(tableExpr);\n // Repeatable facet: several roles match any of them.\n const roles = terms.filter((t) => t.key === \"roles\").map((t) => t.value);\n const rows = ALL_ROWS.filter(\n (row) =>\n (roles.length === 0 || roles.includes(row.role)) &&\n terms.every(({ key, value }) => {\n const v = value.toLowerCase();\n if (key === \"roles\") return true;\n if (key === \"status\") return row.status.toLowerCase().includes(v);\n if (key === \"joined_from\") return row.joined >= value;\n // default: search by name\n return row.name.toLowerCase().includes(v);\n }),\n );\n const [order] = tableSorting;\n if (!order) return rows;\n const field = order.id as keyof SampleRow;\n const sorted = [...rows].sort((a, b) => a[field].localeCompare(b[field]));\n return order.desc ? sorted.reverse() : sorted;\n }, [tableExpr, tableSorting]);\n\n const tableData = useMemo(\n () => ({\n data: filteredRows,\n meta: {\n total: filteredRows.length,\n limit: filteredRows.length,\n offset: 0,\n has_next: false,\n has_prev: false,\n },\n }),\n [filteredRows],\n );\n\n // Section 5: EntitySelect\n const [selectedPatient, setSelectedPatient] = useState<string | null>(null);\n\n return (\n <div className=\"w-full max-w-4xl space-y-6\">\n <div>\n <h1>Data Components</h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n Interactive sandbox for SearchInput (simple, multi-field, faceted,\n free text with filters), EntityTable (with schema editor and custom\n renderers), EntitySelect, and EntityTree.\n </p>\n </div>\n\n {/* Section 1: simple mode */}\n <PlaygroundSection\n title=\"SearchInput — simple mode\"\n description=\"No fields prop. Produces a single search term under the key 'search'.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-4 mb-3\">\n <ToggleStrip\n label=\"Mode\"\n options={MODE_OPTIONS}\n value={simpleMode}\n onChange={(m) => {\n setSimpleMode(m);\n setSimpleExpr(EMPTY_FILTER);\n }}\n format={(m) => MODE_LABELS[m]}\n />\n <ToggleStrip\n label=\"Min chars\"\n options={MIN_CHARS_OPTIONS}\n value={simpleMinChars}\n onChange={setSimpleMinChars}\n format={(n) => (n === 0 ? \"off\" : String(n))}\n />\n </div>\n <SearchInput\n value={simpleExpr}\n onChange={setSimpleExpr}\n mode={simpleMode}\n minChars={simpleMinChars}\n placeholder=\"Search...\"\n className=\"max-w-sm\"\n />\n <FlatTermsInspector expr={simpleExpr} />\n </PlaygroundSection>\n\n {/* Section 1b: searchFields mode */}\n <PlaygroundSection\n title=\"SearchInput — searchFields (multi-field OR)\"\n description=\"Produces a FilterOr with one term per field. Toggle field sets, mode, and minChars to explore different behaviours.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-4 mb-3\">\n <ToggleStrip\n label=\"Fields\"\n options={FIELD_PRESET_INDICES}\n value={fieldsPresetIdx}\n onChange={(idx) => {\n setFieldsPresetIdx(idx);\n setFieldsExpr(EMPTY_FILTER);\n }}\n format={(idx) => SEARCH_FIELD_PRESETS[idx].label}\n />\n <ToggleStrip\n label=\"Mode\"\n options={MODE_OPTIONS}\n value={fieldsMode}\n onChange={(m) => {\n setFieldsMode(m);\n setFieldsExpr(EMPTY_FILTER);\n }}\n format={(m) => MODE_LABELS[m]}\n />\n <ToggleStrip\n label=\"Min chars\"\n options={MIN_CHARS_OPTIONS}\n value={fieldsMinChars}\n onChange={setFieldsMinChars}\n format={(n) => (n === 0 ? \"off\" : String(n))}\n />\n </div>\n <SearchInput\n value={fieldsExpr}\n onChange={setFieldsExpr}\n searchFields={activeSearchFields}\n mode={fieldsMode}\n minChars={fieldsMinChars}\n placeholder={`Search by ${activeSearchFields.join(\" or \")}...`}\n className=\"max-w-sm\"\n />\n <div className=\"mt-3 space-y-2\">\n <p className=\"text-xs text-muted-foreground\">\n searchFields: [{activeSearchFields.map((f) => `\"${f}\"`).join(\", \")}]\n </p>\n <p className=\"text-xs text-muted-foreground\">FilterExpr AST:</p>\n <FilterExprInspector expr={fieldsExpr} />\n {!isEmptyFilterExpr(fieldsExpr) && (\n <>\n <p className=\"text-xs text-muted-foreground\">\n Serialized q= string:\n </p>\n <pre className=\"rounded-md bg-muted px-4 py-3 text-xs overflow-auto\">\n {serializeFilterExpr(fieldsExpr)}\n </pre>\n </>\n )}\n </div>\n </PlaygroundSection>\n\n {/* Section 2: faceted mode -- two-column schema editor */}\n <PlaygroundSection\n title=\"SearchInput — faceted mode\"\n description=\"Edit the JSON Schema on the left and load it into the search input. Add chips by picking a field and typing a value. Press Enter on empty input to fire onChange.\"\n variant=\"card\"\n >\n <div className=\"flex gap-4 items-start\">\n {/* Left: schema editor */}\n <Card className=\"flex-1 min-w-0 p-3 flex flex-col gap-2\">\n <p className=\"text-xs font-medium text-muted-foreground\">\n JSON Schema\n </p>\n {schemaError && (\n <Badge variant=\"destructive\" className=\"text-xs self-start\">\n {schemaError}\n </Badge>\n )}\n <FormTextarea\n value={schemaText}\n onChange={(e) => handleSchemaTextChange(e.target.value)}\n className=\"font-mono text-xs\"\n rows={18}\n />\n </Card>\n\n {/* Load button */}\n <div className=\"flex items-center self-center\">\n <SimpleTooltip label=\"Load schema into search\">\n <Button\n variant=\"default\"\n size=\"icon\"\n onClick={handleLoadSchema}\n disabled={!!schemaError}\n >\n <ArrowRight size={18} />\n </Button>\n </SimpleTooltip>\n </div>\n\n {/* Right: live search + output */}\n <Card className=\"flex-1 min-w-0 p-3 flex flex-col gap-3\">\n <p className=\"text-xs font-medium text-muted-foreground\">\n Live search\n </p>\n <SearchInput\n value={facetedExpr}\n onChange={handleFacetedChange}\n schema={activeSchema}\n mode=\"explicit\"\n placeholder=\"Add filter...\"\n />\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>onChange fired:</span>\n <span className=\"font-mono font-medium text-foreground\">\n {facetedSubmitCount}x\n </span>\n </div>\n <FilterExprInspector expr={facetedExpr} />\n </Card>\n </div>\n </PlaygroundSection>\n\n {/* Section 2b: free text with filters -- one field for both */}\n <PlaygroundSection\n title=\"SearchInput — free text with filters (textKey)\"\n description=\"One field for a query and its filters. Type the query; pick filters with the chevron or ArrowDown. Explicit: Enter submits the text (as the textKey term) with the chips. Debounce: they fire as typing pauses. A removed chip reruns at once; enum chips show their labels.\"\n variant=\"card\"\n >\n <div className=\"flex flex-col gap-3 max-w-2xl\">\n <ToggleStrip\n label=\"Mode\"\n options={MODE_OPTIONS}\n value={freeTextMode}\n onChange={setFreeTextMode}\n format={(m) => MODE_LABELS[m]}\n />\n <SearchInput\n value={freeTextExpr}\n onChange={setFreeTextExpr}\n schema={FREE_TEXT_FACETS}\n textKey=\"q\"\n mode={freeTextMode}\n showSearchButton\n placeholder=\"Search for code or content...\"\n />\n <FilterExprInspector expr={freeTextExpr} />\n </div>\n </PlaygroundSection>\n\n {/* Section 3: faceted mode + EntityTable wired together */}\n <PlaygroundSection\n title=\"EntityTable with SearchInput\"\n description=\"Faceted search wired to EntityTable. onChange fires only on submit (Enter on empty input) -- table filters when the user presses Enter. Role is a repeatable facet (one chip per role) and Joined from uses the date widget. Name and Joined are sortable: click a header -- the table reports the order and the page's query applies it. Density compact tightens the rows and drops the lines between them; layout fill puts the table in a fixed-height box where the rows scroll under a header that stays on top. Edit the JSON Schema or UI Schema below and press Apply to see column changes live.\"\n variant=\"card\"\n >\n <SearchInput\n value={tableExpr}\n onChange={setTableExpr}\n schema={SEARCH_FACET_SCHEMA}\n mode=\"explicit\"\n placeholder=\"Filter users... (press Enter to apply)\"\n className=\"mb-4 max-w-sm\"\n />\n <div className=\"mb-4 flex flex-wrap gap-6\">\n <ToggleStrip\n label=\"Density\"\n options={DENSITY_OPTIONS}\n value={tableDensity}\n onChange={setTableDensity}\n />\n <ToggleStrip\n label=\"Layout\"\n options={LAYOUT_OPTIONS}\n value={tableLayout}\n onChange={setTableLayout}\n />\n </div>\n <div className={tableLayout === \"fill\" ? \"h-64\" : undefined}>\n <EntityTable<SampleRow>\n schema={activeTableSchema}\n uiSchema={activeTableUiSchema}\n data={tableData}\n isLoading={false}\n isError={false}\n entityLabel=\"users\"\n isFiltered={!isEmptyFilterExpr(tableExpr)}\n sorting={tableSorting}\n onSortingChange={setTableSorting}\n density={tableDensity}\n fill={tableLayout === \"fill\"}\n />\n </div>\n\n {/* Schema editor below the table */}\n <div className=\"mt-4\">\n <Card className=\"border shadow-sm p-4 flex flex-col\">\n <div className=\"flex items-center justify-between mb-2\">\n <Tabs\n value={tableSchemaTab}\n onValueChange={setTableSchemaTab}\n className=\"flex flex-col flex-1\"\n >\n <div className=\"flex items-center justify-between\">\n <TabsList>\n <TabsTrigger value=\"schema\">JSON Schema</TabsTrigger>\n <TabsTrigger value=\"uischema\">UI Schema</TabsTrigger>\n </TabsList>\n <div className=\"flex items-center gap-2\">\n {tableSchemaError && (\n <Badge variant=\"destructive\" className=\"text-xs\">\n {tableSchemaError}\n </Badge>\n )}\n <SimpleTooltip label=\"Apply schema to table above\">\n <Button\n variant=\"default\"\n size=\"icon\"\n onClick={handleApplyTableSchema}\n disabled={!!tableSchemaError}\n >\n <ArrowUp size={18} />\n </Button>\n </SimpleTooltip>\n </div>\n </div>\n <TabsContent value=\"schema\" className=\"mt-2\">\n <JsonEditor\n value={tableSchemaText}\n editablePaths={[\"/\"]}\n onChange={handleTableSchemaTextChange}\n height=\"280px\"\n className=\"rounded-md border overflow-hidden\"\n />\n </TabsContent>\n <TabsContent value=\"uischema\" className=\"mt-2\">\n <JsonEditor\n value={tableUiSchemaText}\n editablePaths={[\"/\"]}\n onChange={handleTableUiSchemaTextChange}\n height=\"280px\"\n className=\"rounded-md border overflow-hidden\"\n />\n </TabsContent>\n </Tabs>\n </div>\n </Card>\n </div>\n </PlaygroundSection>\n\n <EntityTableLongListDemo />\n\n {/* Section 4: Local renderers demo */}\n <PlaygroundSection\n title=\"EntityTable with Local Renderers\"\n description=\"Same sample data rendered with x- prefixed local renderers passed via the renderers prop. The schema is pure data -- renderer functions live in code and are resolved by name. Three custom renderers: x-play-initials (avatar from name), x-play-role-icon (letter prefix from options), x-play-tenure (computed days with threshold).\"\n variant=\"card\"\n >\n <EntityTable<SampleRow>\n schema={CUSTOM_RENDERER_SCHEMA}\n renderers={CUSTOM_RENDERERS}\n data={{\n data: ALL_ROWS,\n meta: {\n total: ALL_ROWS.length,\n limit: ALL_ROWS.length,\n offset: 0,\n has_next: false,\n has_prev: false,\n },\n }}\n isLoading={false}\n isError={false}\n entityLabel=\"users\"\n />\n </PlaygroundSection>\n\n {/* Section 5: EntitySelect -- searchable select with mock fetcher */}\n <PlaygroundSection\n title=\"EntitySelect\"\n description=\"Searchable single-select backed by a static mock patient fetcher. Search text is filtered client-side. Available as a form widget via x-ui-widget: 'entity-select'.\"\n variant=\"card\"\n >\n <div className=\"flex gap-6 items-start\">\n <EntitySelect\n fetcher={patientFetcher}\n queryKey=\"playground-patients\"\n value={selectedPatient}\n onChange={setSelectedPatient}\n label=\"Patient\"\n placeholder=\"Select patient...\"\n searchPlaceholder=\"Search patients...\"\n className=\"max-w-xs\"\n />\n <Card className=\"flex-1 min-w-0 p-3\">\n <p className=\"text-xs font-medium text-muted-foreground mb-2\">\n Selected value\n </p>\n <pre className=\"rounded-md bg-muted px-4 py-3 text-xs overflow-auto\">\n {JSON.stringify(selectedPatient, null, 2)}\n </pre>\n </Card>\n </div>\n </PlaygroundSection>\n\n {/* Section 6: EntityTree -- schema-driven tree with static nested data */}\n <PlaygroundSection\n title=\"EntityTree\"\n description=\"Schema-driven tree component built on TreeView. Columns are resolved from a JSON Schema using the same resolveColumns pipeline as EntityTable. Supports expand/collapse, row selection, loading/error/empty states, and custom cell renderers.\"\n variant=\"card\"\n >\n <EntityTreeDemo />\n </PlaygroundSection>\n\n {/* Section 7: PropertyList -- read-only stacked property display */}\n <PlaygroundSection\n title=\"PropertyList\"\n description=\"Read-only property display used by detail pages, panels and graph node/edge cards. With no schema, values render by JS shape; an optional per-property schema refines rendering (date/datetime/boolean/number/x-ui-cell). With an object schema, the schema decides the fields, their order, labels (x-ui-title) and cells (x-ui-cell, or a local x- renderer), as for EntityTable. Density: compact (an inspector) or comfortable (a detail page: label column, no rules between rows).\"\n variant=\"card\"\n >\n <PropertyListDemo />\n </PlaygroundSection>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PropertyList demo\n// ---------------------------------------------------------------------------\n\nconst PROPERTY_LIST_SAMPLE: Record<string, unknown> = {\n name: \"acme_server.api\",\n description: \"Build tools (Maven, Gradle, Webpack, Vite, etc.)\",\n is_component: false,\n tags: [\"python\", \"fastapi\", \"graph\"],\n created_at: \"2026-01-15T09:30:00Z\",\n empty_value: null,\n // Real nested object -> collapsed JSON tree.\n config: {\n retries: 3,\n timeout_s: 30,\n endpoints: [\"/a\", \"/b\"],\n nested: { enabled: true },\n },\n // Long text -> clamp + show more.\n notes:\n \"This module exposes the public API surface. \" +\n \"It aggregates routers from submodules, wires middleware, and configures CORS. \" +\n \"See the architecture doc for the full request lifecycle and the list of mounted sub-applications.\",\n};\n\nconst PROPERTY_LIST_SCHEMA: Record<string, JsonSchemaProperty> = {\n is_component: { type: \"boolean\" },\n created_at: { type: \"string\", format: \"date-time\" },\n};\n\nfunction PropertyListDemo(): React.ReactElement {\n return (\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2\">\n <Card className=\"p-4\">\n <p className=\"mb-3 text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n No schema (value-shape)\n </p>\n <PropertyList properties={PROPERTY_LIST_SAMPLE} />\n </Card>\n <Card className=\"p-4\">\n <p className=\"mb-3 text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n With optional schema (boolean / date-time)\n </p>\n <PropertyList\n properties={PROPERTY_LIST_SAMPLE}\n propertySchemas={PROPERTY_LIST_SCHEMA}\n showHeader\n />\n </Card>\n <Card className=\"p-4 sm:col-span-2\">\n <p className=\"mb-3 text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n Object schema, comfortable (a detail page)\n </p>\n <PropertyList\n properties={DETAIL_SAMPLE}\n schema={DETAIL_SCHEMA}\n renderers={DETAIL_RENDERERS}\n density=\"comfortable\"\n copyable={false}\n />\n </Card>\n </div>\n );\n}\n\n// A detail page's view: fields in schema order, labels from x-ui-title, cells\n// from x-ui-cell -- built-in (code, badge, datetime, join) or local (x-links).\nconst DetailSchema = z.object({\n program: z.string().meta({ \"x-ui-title\": \"Program\", \"x-ui-cell\": \"code\" }),\n status: z.string().meta({\n \"x-ui-title\": \"Status\",\n \"x-ui-cell\": \"badge\",\n \"x-ui-cell-options\": { colors: { available: \"green\", missing: \"red\" } },\n }),\n exit_codes: z.array(z.number()).meta({ \"x-ui-title\": \"Success exit codes\" }),\n version_args: z.array(z.string()).meta({\n \"x-ui-title\": \"Version check\",\n \"x-ui-cell\": \"join\",\n \"x-ui-cell-options\": { separator: \" \" },\n }),\n used_by: z\n .array(z.string())\n .meta({ \"x-ui-title\": \"Run by\", \"x-ui-cell\": \"x-links\" }),\n updated_at: z.string().meta({ \"x-ui-title\": \"Updated\", format: \"date-time\" }),\n internal_id: z.string().meta({ \"x-ui-column\": { hidden: true } }),\n});\n\nconst DETAIL_SCHEMA = toJsonSchema(DetailSchema);\n\nconst DETAIL_SAMPLE: Record<string, unknown> = {\n program: \"trivy\",\n status: \"available\",\n exit_codes: [0, 1],\n version_args: [\"--version\"],\n used_by: [\"acme.scan\", \"acme.nightly\"],\n updated_at: \"2026-10-30T14:05:00Z\",\n internal_id: \"not shown\",\n};\n\nconst DETAIL_RENDERERS = {\n \"x-links\": createRenderer((row) => {\n const items = (row.used_by as string[] | undefined) ?? [];\n if (!items.length)\n return <span className=\"text-muted-foreground\">none</span>;\n return items.map((item, i) => (\n <React.Fragment key={item}>\n {i > 0 && \", \"}\n <a href=\"#\" className=\"text-primary hover:underline\">\n {item}\n </a>\n </React.Fragment>\n ));\n }),\n};\n\n// ---------------------------------------------------------------------------\n// EntityTree demo\n// ---------------------------------------------------------------------------\n\ninterface OrgRow extends Record<string, unknown> {\n name: string;\n type: string;\n headcount: number;\n}\n\nconst OrgSchema = z.object({\n name: z.string().meta({ title: \"Name\", \"x-ui-column\": { order: 0 } }),\n type: z.string().meta({ title: \"Type\", \"x-ui-column\": { order: 1 } }),\n headcount: z\n .number()\n .meta({ title: \"Headcount\", \"x-ui-column\": { order: 2 } }),\n});\n\nconst ORG_TREE_SCHEMA = toJsonSchema(OrgSchema);\n\nconst ORG_NODES: TreeNode<OrgRow>[] = [\n {\n id: \"eng\",\n data: { name: \"Engineering\", type: \"Division\", headcount: 120 },\n hasChildren: true,\n children: [\n {\n id: \"frontend\",\n data: { name: \"Frontend\", type: \"Team\", headcount: 18 },\n hasChildren: true,\n children: [\n {\n id: \"design-sys\",\n data: { name: \"Design System\", type: \"Squad\", headcount: 5 },\n hasChildren: false,\n },\n ],\n },\n {\n id: \"backend\",\n data: { name: \"Backend\", type: \"Team\", headcount: 32 },\n hasChildren: false,\n },\n {\n id: \"infra\",\n data: { name: \"Infrastructure\", type: \"Team\", headcount: 14 },\n hasChildren: false,\n },\n ],\n },\n {\n id: \"product\",\n data: { name: \"Product\", type: \"Division\", headcount: 45 },\n hasChildren: true,\n children: [\n {\n id: \"research\",\n data: { name: \"Research\", type: \"Team\", headcount: 8 },\n hasChildren: false,\n },\n {\n id: \"pm\",\n data: { name: \"Product Management\", type: \"Team\", headcount: 12 },\n hasChildren: false,\n },\n ],\n },\n {\n id: \"ops\",\n data: { name: \"Operations\", type: \"Division\", headcount: 30 },\n hasChildren: false,\n },\n];\n\nfunction EntityTreeDemo() {\n const {\n expandedIds: treeExpandedIds,\n onExpand: onTreeExpand,\n onCollapse: onTreeCollapse,\n } = useTreeExpansion();\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());\n const [activeId, setActiveId] = useState<string | null>(null);\n\n return (\n <div className=\"space-y-4\">\n <EntityTree<OrgRow>\n schema={ORG_TREE_SCHEMA}\n nodes={ORG_NODES}\n expandedIds={treeExpandedIds}\n onExpand={onTreeExpand}\n onCollapse={onTreeCollapse}\n onNodeSelect={(node) => setActiveId(node.id)}\n onNodeEdit={(node) => setActiveId(node.id)}\n activeNodeId={activeId ?? undefined}\n selectedIds={selectedIds}\n onSelectionChange={(id, selected) =>\n setSelectedIds((prev) => {\n const next = new Set(prev);\n if (selected) next.add(id);\n else next.delete(id);\n return next;\n })\n }\n entityLabel=\"departments\"\n />\n <div className=\"flex gap-6 text-xs text-muted-foreground\">\n {activeId && (\n <span>\n Active: <span className=\"font-mono\">{activeId}</span>\n </span>\n )}\n {selectedIds.size > 0 && (\n <span>\n Selected:{\" \"}\n <span className=\"font-mono\">{[...selectedIds].join(\", \")}</span>\n </span>\n )}\n </div>\n </div>\n );\n}\n","/**\n * EntityTable on a long list: 5,000 generated rows in a fill box, compact, to\n * try how the rows arrive -- in pages, with a \"Load more\" footer, or loaded as\n * the end scrolls into view -- and virtual rows (only the rows in view are in\n * the DOM). The \"server\" is in memory, a page answered after a short delay so\n * the loading states show.\n */\nimport React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n EntityTable,\n type PaginationState,\n type TableLoadMore,\n} from \"@petrarca/sonnet-ui\";\nimport type { JsonSchema } from \"@petrarca/sonnet-core/schema\";\nimport { PlaygroundSection } from \"../PlaygroundSection\";\n\ninterface FileRow {\n id: string;\n name: string;\n folder: string;\n size: number;\n}\n\nconst TOTAL = 5000;\nconst PAGE_SIZE = 100;\nconst DELAY_MS = 300;\n\nconst ROWS: FileRow[] = Array.from({ length: TOTAL }, (_, i) => ({\n id: `f-${i}`,\n name: `file-${String(i).padStart(4, \"0\")}.ts`,\n folder: `src/module-${i % 37}/part-${i % 7}`,\n size: (i * 7919) % 400,\n}));\n\nconst SCHEMA: JsonSchema = {\n title: \"File\",\n type: \"object\",\n properties: {\n name: { type: \"string\", title: \"Name\", \"x-ui-cell\": \"code\" },\n size: { type: \"number\", title: \"Chunks\" },\n folder: { type: \"string\", title: \"Folder\", \"x-ui-cell\": \"muted\" },\n },\n};\n\nconst PAGINGS = [\"pages\", \"load more\", \"on scroll\"] as const;\ntype Paging = (typeof PAGINGS)[number];\n\nconst page = (rows: FileRow[]) => ({\n data: rows,\n meta: {\n total: TOTAL,\n limit: rows.length,\n offset: 0,\n has_next: rows.length < TOTAL,\n has_prev: false,\n },\n});\n\n// Rows loaded progressively: a page at a time, after a delay.\nfunction useProgressiveRows(paging: Paging): {\n rows: FileRow[];\n loadMore: TableLoadMore;\n} {\n const [loaded, setLoaded] = useState(PAGE_SIZE);\n const [isLoading, setIsLoading] = useState(false);\n useEffect(() => setLoaded(PAGE_SIZE), [paging]);\n const onLoadMore = useCallback(() => {\n setIsLoading(true);\n window.setTimeout(() => {\n setLoaded((n) => Math.min(n + PAGE_SIZE, TOTAL));\n setIsLoading(false);\n }, DELAY_MS);\n }, []);\n return {\n rows: ROWS.slice(0, loaded),\n loadMore: {\n hasMore: loaded < TOTAL,\n isLoading,\n onLoadMore,\n auto: paging === \"on scroll\",\n },\n };\n}\n\nfunction Toggle<T extends string>({\n label,\n options,\n value,\n onChange,\n}: {\n label: string;\n options: readonly T[];\n value: T;\n onChange: (v: T) => void;\n}): React.ReactElement {\n return (\n <div className=\"flex items-center gap-2\" role=\"group\" aria-label={label}>\n <span className=\"text-xs text-muted-foreground\">{label}:</span>\n {options.map((option) => (\n <button\n key={option}\n type=\"button\"\n aria-pressed={option === value}\n onClick={() => onChange(option)}\n className={\n option === value\n ? \"rounded-full bg-primary px-3 py-1 text-xs font-medium text-primary-foreground\"\n : \"rounded-full bg-muted px-3 py-1 text-xs font-medium text-muted-foreground hover:text-foreground\"\n }\n >\n {option}\n </button>\n ))}\n </div>\n );\n}\n\nexport function EntityTableLongListDemo(): React.ReactElement {\n const [paging, setPaging] = useState<Paging>(\"on scroll\");\n const [virtual, setVirtual] = useState<\"off\" | \"on\">(\"on\");\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: PAGE_SIZE,\n });\n const progressive = useProgressiveRows(paging);\n const paged = useMemo(() => {\n const from = pagination.pageIndex * pagination.pageSize;\n return ROWS.slice(from, from + pagination.pageSize);\n }, [pagination]);\n\n const byPages = paging === \"pages\";\n return (\n <PlaygroundSection\n title=\"EntityTable on a long list\"\n description=\"5,000 rows in a fill box (compact). Pages: the page controls. Load more: a footer button adds the next 100 rows. On scroll: the next rows load as the end comes into view (no button needed). Virtual rows: only the rows in view are rendered -- open the DOM inspector and scroll.\"\n variant=\"card\"\n >\n <div className=\"mb-4 flex flex-wrap gap-6\">\n <Toggle\n label=\"Rows\"\n options={PAGINGS}\n value={paging}\n onChange={setPaging}\n />\n <Toggle\n label=\"Virtual rows\"\n options={[\"off\", \"on\"] as const}\n value={virtual}\n onChange={setVirtual}\n />\n </div>\n <div className=\"h-80\">\n <EntityTable<FileRow>\n schema={SCHEMA}\n data={page(byPages ? paged : progressive.rows)}\n isLoading={false}\n isError={false}\n entityLabel=\"files\"\n density=\"compact\"\n fill\n virtualize={virtual === \"on\"}\n getRowId={(row) => row.id}\n {...(byPages\n ? { pagination, onPaginationChange: setPagination }\n : { loadMore: progressive.loadMore })}\n />\n </div>\n </PlaygroundSection>\n );\n}\n"],"mappings":"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","names":["React","useState","useMemo","useCallback","EntityTable","jsx","jsxs","useState","useCallback","useMemo","EntityTable","React"]}
|
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
} from "./chunk-C2EZ2ECG.js";
|
|
4
4
|
|
|
5
5
|
// src/pages/PlayShellApi.tsx
|
|
6
|
+
import { useState } from "react";
|
|
6
7
|
import { Button } from "@petrarca/sonnet-ui";
|
|
7
8
|
import {
|
|
9
|
+
useCollapsedSubNav,
|
|
8
10
|
notification,
|
|
9
11
|
dialog,
|
|
10
12
|
navigation,
|
|
@@ -13,6 +15,8 @@ import {
|
|
|
13
15
|
} from "@petrarca/sonnet-shell";
|
|
14
16
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
17
|
function PlayShellApi() {
|
|
18
|
+
const [focused, setFocused] = useState(false);
|
|
19
|
+
useCollapsedSubNav(focused);
|
|
16
20
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
17
21
|
/* @__PURE__ */ jsx(
|
|
18
22
|
PlaygroundSection,
|
|
@@ -57,6 +61,21 @@ function PlayShellApi() {
|
|
|
57
61
|
children: "info()"
|
|
58
62
|
}
|
|
59
63
|
),
|
|
64
|
+
/* @__PURE__ */ jsx(
|
|
65
|
+
Button,
|
|
66
|
+
{
|
|
67
|
+
variant: "outline",
|
|
68
|
+
size: "sm",
|
|
69
|
+
onClick: () => notification.success("Flow assigned to product.", {
|
|
70
|
+
description: "acme reads its default.",
|
|
71
|
+
action: {
|
|
72
|
+
label: "Give acme its own value",
|
|
73
|
+
onClick: () => notification.info("Opening acme's value.")
|
|
74
|
+
}
|
|
75
|
+
}),
|
|
76
|
+
children: "success() with action"
|
|
77
|
+
}
|
|
78
|
+
),
|
|
60
79
|
/* @__PURE__ */ jsx(
|
|
61
80
|
Button,
|
|
62
81
|
{
|
|
@@ -111,6 +130,26 @@ function PlayShellApi() {
|
|
|
111
130
|
children: "confirm() \u2014 destructive"
|
|
112
131
|
}
|
|
113
132
|
),
|
|
133
|
+
/* @__PURE__ */ jsx(
|
|
134
|
+
Button,
|
|
135
|
+
{
|
|
136
|
+
variant: "outline",
|
|
137
|
+
size: "sm",
|
|
138
|
+
onClick: async () => {
|
|
139
|
+
const confirmed = await dialog.confirm({
|
|
140
|
+
title: "Delete source acme-billing",
|
|
141
|
+
description: "Removes the source and everything indexed from it.",
|
|
142
|
+
confirmLabel: "Delete",
|
|
143
|
+
variant: "destructive",
|
|
144
|
+
confirmText: "acme-billing"
|
|
145
|
+
});
|
|
146
|
+
notification.info(
|
|
147
|
+
confirmed ? "User confirmed." : "User cancelled."
|
|
148
|
+
);
|
|
149
|
+
},
|
|
150
|
+
children: "confirm() \u2014 type the name"
|
|
151
|
+
}
|
|
152
|
+
),
|
|
114
153
|
/* @__PURE__ */ jsx(
|
|
115
154
|
Button,
|
|
116
155
|
{
|
|
@@ -315,6 +354,23 @@ function PlayShellApi() {
|
|
|
315
354
|
] })
|
|
316
355
|
}
|
|
317
356
|
),
|
|
357
|
+
/* @__PURE__ */ jsx(
|
|
358
|
+
PlaygroundSection,
|
|
359
|
+
{
|
|
360
|
+
title: "useCollapsedSubNav",
|
|
361
|
+
description: "A page that needs the full content width (a canvas, an editor) collapses the sub-navigation while it is shown. Leaving the page restores the user's own setting; the user can still expand it meanwhile.",
|
|
362
|
+
variant: "card",
|
|
363
|
+
children: /* @__PURE__ */ jsx(
|
|
364
|
+
Button,
|
|
365
|
+
{
|
|
366
|
+
variant: "outline",
|
|
367
|
+
size: "sm",
|
|
368
|
+
onClick: () => setFocused((f) => !f),
|
|
369
|
+
children: focused ? "useCollapsedSubNav(false)" : "useCollapsedSubNav(true)"
|
|
370
|
+
}
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
),
|
|
318
374
|
/* @__PURE__ */ jsx(
|
|
319
375
|
PlaygroundSection,
|
|
320
376
|
{
|
|
@@ -338,4 +394,4 @@ function PlayShellApi() {
|
|
|
338
394
|
export {
|
|
339
395
|
PlayShellApi
|
|
340
396
|
};
|
|
341
|
-
//# sourceMappingURL=chunk-
|
|
397
|
+
//# sourceMappingURL=chunk-3RZHYZRL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pages/PlayShellApi.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"@petrarca/sonnet-ui\";\nimport {\n useCollapsedSubNav,\n notification,\n dialog,\n navigation,\n panel,\n sidePane,\n} from \"@petrarca/sonnet-shell\";\nimport { PlaygroundSection } from \"../PlaygroundSection\";\n\n/**\n * PlayShellApi -- playground page that exercises the shell API surface.\n *\n * Covers: notification, dialog, navigation, panel, sidePane,\n * the command menu (Cmd+K), and useCollapsedSubNav.\n */\nexport default function PlayShellApi() {\n const [focused, setFocused] = useState(false);\n useCollapsedSubNav(focused);\n return (\n <div className=\"space-y-6\">\n {/* ── notification ─────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"notification\"\n description=\"Toasts via the shell notification API — wraps Sonner.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.success(\"Operation completed.\")}\n >\n success()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.error(\"Something went wrong.\")}\n >\n error()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.warning(\"Proceed with caution.\")}\n >\n warning()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.info(\"Here is some information.\")}\n >\n info()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n notification.success(\"Flow assigned to product.\", {\n description: \"acme reads its default.\",\n action: {\n label: \"Give acme its own value\",\n onClick: () => notification.info(\"Opening acme's value.\"),\n },\n })\n }\n >\n success() with action\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n notification.promise(\n new Promise((resolve) => setTimeout(resolve, 2000)),\n {\n loading: \"Loading...\",\n success: \"Done!\",\n error: \"Failed.\",\n },\n )\n }\n >\n promise()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.dismiss()}\n >\n dismiss()\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── dialog ───────────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"dialog\"\n description=\"Confirmation dialog via the shell dialog API.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={async () => {\n const confirmed = await dialog.confirm({\n title: \"Delete Resource\",\n description:\n \"This will permanently delete the resource. Are you sure?\",\n confirmLabel: \"Delete\",\n variant: \"destructive\",\n });\n notification.info(\n confirmed ? \"User confirmed.\" : \"User cancelled.\",\n );\n }}\n >\n confirm() — destructive\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={async () => {\n const confirmed = await dialog.confirm({\n title: \"Delete source acme-billing\",\n description:\n \"Removes the source and everything indexed from it.\",\n confirmLabel: \"Delete\",\n variant: \"destructive\",\n confirmText: \"acme-billing\",\n });\n notification.info(\n confirmed ? \"User confirmed.\" : \"User cancelled.\",\n );\n }}\n >\n confirm() — type the name\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={async () => {\n const confirmed = await dialog.confirm({\n title: \"Save Changes\",\n description: \"Do you want to save your changes?\",\n });\n notification.info(\n confirmed ? \"User confirmed.\" : \"User cancelled.\",\n );\n }}\n >\n confirm() — default\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── navigation ───────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"navigation\"\n description=\"Programmatic navigation via the shell navigation API.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigation.goTo(\"/home\")}\n >\n goTo(\"/home\")\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigation.goTo(\"/playground\")}\n >\n goTo(\"/playground\")\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigation.openCommandMenu()}\n >\n openCommandMenu()\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigation.back()}>\n back()\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── panel ────────────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"panel\"\n description=\"Shell-managed slide-over panel — renders content inside a Sheet owned by the shell.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n panel.open({\n title: \"Panel Demo\",\n description: \"This is a shell-managed slide-over panel.\",\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm\">\n This content is rendered inside the shell's Sheet\n component.\n </p>\n <p className=\"text-xs text-muted-foreground\">\n Use <code>panel.open()</code> to show any React content in\n a slide-over panel.\n </p>\n </div>\n ),\n })\n }\n >\n open() — narrow\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n panel.open({\n title: \"Wide Panel\",\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Wide panel (default)</p>\n <p className=\"text-xs text-muted-foreground\">\n width=\"default\" gives a wider panel for more complex\n content.\n </p>\n </div>\n ),\n width: \"default\",\n })\n }\n >\n open() — default width\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n panel.open({\n title: \"Full Coverage\",\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Full coverage panel</p>\n <p className=\"text-xs text-muted-foreground\">\n coverage=\"full\" overlays the entire content area.\n </p>\n </div>\n ),\n width: \"default\",\n coverage: \"full\",\n })\n }\n >\n open() — full coverage\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n panel.open({\n title: \"Resizable Panel\",\n description:\n \"Drag the left edge to resize. Double-click to reset.\",\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Resizable panel</p>\n <p className=\"text-xs text-muted-foreground\">\n resizable=true · defaultWidth=640 · minWidth=320 ·\n maxWidth=1000\n </p>\n </div>\n ),\n width: \"default\",\n resizable: true,\n minWidth: 320,\n maxWidth: 1000,\n })\n }\n >\n open() — resizable\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── sidePane ─────────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"sidePane\"\n description=\"Persistent inline resizable panel. Sits beside the content area — the main view shrinks rather than being overlaid. Drag the edge to resize; double-click to reset.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n sidePane.open({\n moduleId: \"shell-demo-narrow\",\n defaultWidth: 240,\n minWidth: 180,\n maxWidth: 400,\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Narrow pane (240px)</p>\n <p className=\"text-xs text-muted-foreground\">\n defaultWidth=240 minWidth=180 maxWidth=400\n </p>\n </div>\n ),\n })\n }\n >\n open() — narrow\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n sidePane.open({\n moduleId: \"shell-demo-wide\",\n defaultWidth: 480,\n minWidth: 320,\n maxWidth: 800,\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Wide pane (480px)</p>\n <p className=\"text-xs text-muted-foreground\">\n defaultWidth=480 minWidth=320 maxWidth=800\n </p>\n </div>\n ),\n })\n }\n >\n open() — wide\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n sidePane.toggle({\n moduleId: \"shell-demo-toggle\",\n defaultWidth: 320,\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Toggle pane</p>\n <p className=\"text-xs text-muted-foreground\">\n Click again to close. Same moduleId toggles.\n </p>\n </div>\n ),\n })\n }\n >\n toggle()\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => sidePane.close()}>\n close()\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── useCollapsedSubNav ───────────────────────────────────── */}\n <PlaygroundSection\n title=\"useCollapsedSubNav\"\n description=\"A page that needs the full content width (a canvas, an editor) collapses the sub-navigation while it is shown. Leaving the page restores the user's own setting; the user can still expand it meanwhile.\"\n variant=\"card\"\n >\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setFocused((f) => !f)}\n >\n {focused ? \"useCollapsedSubNav(false)\" : \"useCollapsedSubNav(true)\"}\n </Button>\n </PlaygroundSection>\n\n {/* ── CommandMenu (Cmd+K) ──────────────────────────────────── */}\n <PlaygroundSection\n title=\"CommandMenu (Cmd+K)\"\n description=\"Open the command palette programmatically. Modules can register commands that appear here via the commands array in their ShellModule definition.\"\n variant=\"card\"\n >\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigation.openCommandMenu()}\n >\n Open CommandMenu\n </Button>\n </PlaygroundSection>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PlaygroundSection
|
|
3
|
+
} from "./chunk-C2EZ2ECG.js";
|
|
4
|
+
|
|
5
|
+
// src/pages/PlayMarkdownViewer.tsx
|
|
6
|
+
import { useEffect, useState } from "react";
|
|
7
|
+
import { MarkdownViewer } from "@petrarca/sonnet-ui/markdown";
|
|
8
|
+
import { Button } from "@petrarca/sonnet-ui";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
var DOCUMENT = `# Release notes
|
|
11
|
+
|
|
12
|
+
The **file browser** shows a tree by source and folder; a *search hit* opens
|
|
13
|
+
the file at its lines. ~~Flat list only~~ is gone.
|
|
14
|
+
|
|
15
|
+
## What changed
|
|
16
|
+
|
|
17
|
+
- [x] Folders open page by page
|
|
18
|
+
- [x] Files show in the code editor
|
|
19
|
+
- [ ] An outline from the code graph
|
|
20
|
+
|
|
21
|
+
| Area | Before | After |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| Files | flat table | tree + viewer |
|
|
24
|
+
| Search | two forms | one field |
|
|
25
|
+
|
|
26
|
+
\`\`\`python
|
|
27
|
+
def handler(request: dict) -> dict:
|
|
28
|
+
"""Answer one request."""
|
|
29
|
+
return {"ok": True, "items": [1, 2, 3]}
|
|
30
|
+
\`\`\`
|
|
31
|
+
|
|
32
|
+
\`\`\`mermaid
|
|
33
|
+
graph LR
|
|
34
|
+
Search -->|hit| Files
|
|
35
|
+
Files --> Viewer
|
|
36
|
+
Viewer --> Metadata
|
|
37
|
+
\`\`\`
|
|
38
|
+
|
|
39
|
+
> Raw HTML is sanitized: <b>bold</b> stays, scripts and handlers go.
|
|
40
|
+
`;
|
|
41
|
+
var ANSWER = "The query found **3 sources**. The largest is `acme-platform`:\n\n```cypher\nMATCH (s:Source) RETURN s.name, s.files ORDER BY s.files DESC\n```\n\n| Source | Files |\n|---|---|\n| acme-platform | 19978 |\n| acme-portal | 799 |";
|
|
42
|
+
function useStreamedText(text, run) {
|
|
43
|
+
const [shown, setShown] = useState("");
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
setShown("");
|
|
46
|
+
let at = 0;
|
|
47
|
+
const timer = setInterval(() => {
|
|
48
|
+
at = Math.min(text.length, at + 6);
|
|
49
|
+
setShown(text.slice(0, at));
|
|
50
|
+
if (at === text.length) clearInterval(timer);
|
|
51
|
+
}, 40);
|
|
52
|
+
return () => clearInterval(timer);
|
|
53
|
+
}, [text, run]);
|
|
54
|
+
return { shown, done: shown.length === text.length };
|
|
55
|
+
}
|
|
56
|
+
function PlayMarkdownViewer() {
|
|
57
|
+
const [run, setRun] = useState(0);
|
|
58
|
+
const { shown, done } = useStreamedText(ANSWER, run);
|
|
59
|
+
return /* @__PURE__ */ jsxs("div", { className: "w-full max-w-4xl space-y-6", children: [
|
|
60
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
61
|
+
/* @__PURE__ */ jsx("h1", { children: "Markdown Viewer" }),
|
|
62
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Markdown for reading: GitHub-flavoured, code blocks in the code editor, Mermaid diagrams (loaded only when a document has one), and untrusted content sanitized." })
|
|
63
|
+
] }),
|
|
64
|
+
/* @__PURE__ */ jsx(
|
|
65
|
+
PlaygroundSection,
|
|
66
|
+
{
|
|
67
|
+
title: "A document",
|
|
68
|
+
description: "Headings, emphasis, a task list, a table, a code block, a diagram, and sanitized raw HTML.",
|
|
69
|
+
variant: "card",
|
|
70
|
+
children: /* @__PURE__ */ jsx(MarkdownViewer, { content: DOCUMENT })
|
|
71
|
+
}
|
|
72
|
+
),
|
|
73
|
+
/* @__PURE__ */ jsxs(
|
|
74
|
+
PlaygroundSection,
|
|
75
|
+
{
|
|
76
|
+
title: "A streamed answer",
|
|
77
|
+
description: "streaming: incomplete Markdown is closed as it arrives and new text fades in -- for a chat.",
|
|
78
|
+
variant: "card",
|
|
79
|
+
children: [
|
|
80
|
+
/* @__PURE__ */ jsx(MarkdownViewer, { content: shown, streaming: !done }),
|
|
81
|
+
/* @__PURE__ */ jsx(
|
|
82
|
+
Button,
|
|
83
|
+
{
|
|
84
|
+
variant: "outline",
|
|
85
|
+
size: "sm",
|
|
86
|
+
className: "mt-3",
|
|
87
|
+
onClick: () => setRun((n) => n + 1),
|
|
88
|
+
children: "Stream again"
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
] });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export {
|
|
98
|
+
PlayMarkdownViewer
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=chunk-7IMCPUSI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pages/PlayMarkdownViewer.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { MarkdownViewer } from \"@petrarca/sonnet-ui/markdown\";\nimport { Button } from \"@petrarca/sonnet-ui\";\nimport { PlaygroundSection } from \"../PlaygroundSection\";\n\nconst DOCUMENT = `# Release notes\n\nThe **file browser** shows a tree by source and folder; a *search hit* opens\nthe file at its lines. ~~Flat list only~~ is gone.\n\n## What changed\n\n- [x] Folders open page by page\n- [x] Files show in the code editor\n- [ ] An outline from the code graph\n\n| Area | Before | After |\n|---|---|---|\n| Files | flat table | tree + viewer |\n| Search | two forms | one field |\n\n\\`\\`\\`python\ndef handler(request: dict) -> dict:\n \"\"\"Answer one request.\"\"\"\n return {\"ok\": True, \"items\": [1, 2, 3]}\n\\`\\`\\`\n\n\\`\\`\\`mermaid\ngraph LR\n Search -->|hit| Files\n Files --> Viewer\n Viewer --> Metadata\n\\`\\`\\`\n\n> Raw HTML is sanitized: <b>bold</b> stays, scripts and handlers go.\n`;\n\nconst ANSWER =\n \"The query found **3 sources**. The largest is `acme-platform`:\\n\\n\" +\n \"```cypher\\nMATCH (s:Source) RETURN s.name, s.files ORDER BY s.files DESC\\n```\\n\\n\" +\n \"| Source | Files |\\n|---|---|\\n| acme-platform | 19978 |\\n| acme-portal | 799 |\";\n\n// The answer arriving a few characters at a time, as a chat would show it.\nfunction useStreamedText(text: string, run: number) {\n const [shown, setShown] = useState(\"\");\n useEffect(() => {\n setShown(\"\");\n let at = 0;\n const timer = setInterval(() => {\n at = Math.min(text.length, at + 6);\n setShown(text.slice(0, at));\n if (at === text.length) clearInterval(timer);\n }, 40);\n return () => clearInterval(timer);\n }, [text, run]);\n return { shown, done: shown.length === text.length };\n}\n\n/** PlayMarkdownViewer -- a document, and a streamed chat answer. */\nexport default function PlayMarkdownViewer() {\n const [run, setRun] = useState(0);\n const { shown, done } = useStreamedText(ANSWER, run);\n return (\n <div className=\"w-full max-w-4xl space-y-6\">\n <div>\n <h1>Markdown Viewer</h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n Markdown for reading: GitHub-flavoured, code blocks in the code\n editor, Mermaid diagrams (loaded only when a document has one), and\n untrusted content sanitized.\n </p>\n </div>\n\n <PlaygroundSection\n title=\"A document\"\n description=\"Headings, emphasis, a task list, a table, a code block, a diagram, and sanitized raw HTML.\"\n variant=\"card\"\n >\n <MarkdownViewer content={DOCUMENT} />\n </PlaygroundSection>\n\n <PlaygroundSection\n title=\"A streamed answer\"\n description=\"streaming: incomplete Markdown is closed as it arrives and new text fades in -- for a chat.\"\n variant=\"card\"\n >\n <MarkdownViewer content={shown} streaming={!done} />\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={() => setRun((n) => n + 1)}\n >\n Stream again\n </Button>\n </PlaygroundSection>\n </div>\n );\n}\n"],"mappings":";;;;;AAAA,SAAS,WAAW,gBAAgB;AACpC,SAAS,sBAAsB;AAC/B,SAAS,cAAc;AA8DjB,SACE,KADF;AA3DN,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCjB,IAAM,SACJ;AAKF,SAAS,gBAAgB,MAAc,KAAa;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,YAAU,MAAM;AACd,aAAS,EAAE;AACX,QAAI,KAAK;AACT,UAAM,QAAQ,YAAY,MAAM;AAC9B,WAAK,KAAK,IAAI,KAAK,QAAQ,KAAK,CAAC;AACjC,eAAS,KAAK,MAAM,GAAG,EAAE,CAAC;AAC1B,UAAI,OAAO,KAAK,OAAQ,eAAc,KAAK;AAAA,IAC7C,GAAG,EAAE;AACL,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,MAAM,GAAG,CAAC;AACd,SAAO,EAAE,OAAO,MAAM,MAAM,WAAW,KAAK,OAAO;AACrD;AAGe,SAAR,qBAAsC;AAC3C,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,CAAC;AAChC,QAAM,EAAE,OAAO,KAAK,IAAI,gBAAgB,QAAQ,GAAG;AACnD,SACE,qBAAC,SAAI,WAAU,8BACb;AAAA,yBAAC,SACC;AAAA,0BAAC,QAAG,6BAAe;AAAA,MACnB,oBAAC,OAAE,WAAU,sCAAqC,8KAIlD;AAAA,OACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SAAQ;AAAA,QAER,8BAAC,kBAAe,SAAS,UAAU;AAAA;AAAA,IACrC;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SAAQ;AAAA,QAER;AAAA,8BAAC,kBAAe,SAAS,OAAO,WAAW,CAAC,MAAM;AAAA,UAClD;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS,MAAM,OAAO,CAAC,MAAM,IAAI,CAAC;AAAA,cACnC;AAAA;AAAA,UAED;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DesignerControls
|
|
3
|
+
} from "./chunk-QKFQI4VX.js";
|
|
4
|
+
|
|
1
5
|
// src/pages/PlaySchemaDesigner.tsx
|
|
2
6
|
import { useState } from "react";
|
|
3
7
|
import {
|
|
4
8
|
SchemaDesigner
|
|
5
9
|
} from "@petrarca/sonnet-schema-designer";
|
|
6
|
-
import { FormSelect } from "@petrarca/sonnet-forms";
|
|
7
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
var CONTACT_SCHEMA = {
|
|
12
|
+
title: "Contact",
|
|
13
|
+
type: "object",
|
|
14
|
+
required: ["name"],
|
|
15
|
+
properties: {
|
|
16
|
+
name: { type: "string", title: "Name" },
|
|
17
|
+
email: { type: "string", format: "email", title: "Email" },
|
|
18
|
+
phone: { type: "string", title: "Phone" },
|
|
19
|
+
newsletter: { type: "boolean", title: "Send me the newsletter" }
|
|
20
|
+
}
|
|
21
|
+
};
|
|
8
22
|
var SAMPLE_SCHEMA = {
|
|
9
23
|
title: "Patient",
|
|
10
24
|
type: "object",
|
|
@@ -216,23 +230,27 @@ var AUDIT_EDITABLE_PATHS = [
|
|
|
216
230
|
"/properties/actor/properties/metadata/properties",
|
|
217
231
|
"/properties/targets/items/properties/metadata/properties"
|
|
218
232
|
];
|
|
233
|
+
var EXAMPLES = {
|
|
234
|
+
simple: { label: "Simple -- contact", schema: CONTACT_SCHEMA },
|
|
235
|
+
medium: { label: "Medium -- patient", schema: SAMPLE_SCHEMA },
|
|
236
|
+
advanced: { label: "Advanced -- checkout (logic)", schema: LOGIC_SCHEMA }
|
|
237
|
+
};
|
|
219
238
|
var PROFILES = {
|
|
220
239
|
full: {
|
|
221
240
|
label: "Full (schema + uiSchema)",
|
|
222
241
|
description: "Default: author the schema and its form presentation hints.",
|
|
223
|
-
schema: SAMPLE_SCHEMA,
|
|
224
242
|
capabilities: { previews: ["form", "table", "json", "capabilities"] }
|
|
225
243
|
},
|
|
226
244
|
data: {
|
|
227
245
|
label: "Data schema only",
|
|
228
246
|
description: "Pure JSON Schema (audit, terminology): no UI/Combined tabs, JSON preview only.",
|
|
229
|
-
schema: SAMPLE_SCHEMA,
|
|
230
247
|
capabilities: { mode: "data", previews: ["json", "capabilities"] }
|
|
231
248
|
},
|
|
232
249
|
scoped: {
|
|
233
250
|
label: "Scoped (audit event)",
|
|
234
|
-
description: "
|
|
251
|
+
description: "Made for an audit event: its fixed envelope locked, only its three metadata containers editable.",
|
|
235
252
|
schema: AUDIT_SCHEMA,
|
|
253
|
+
schemaLabel: "Audit event (the profile's own)",
|
|
236
254
|
capabilities: {
|
|
237
255
|
mode: "data",
|
|
238
256
|
editablePaths: AUDIT_EDITABLE_PATHS,
|
|
@@ -242,56 +260,45 @@ var PROFILES = {
|
|
|
242
260
|
structure: {
|
|
243
261
|
label: "Structure only (no preview)",
|
|
244
262
|
description: "Tree + inspector only; the center preview pane is hidden.",
|
|
245
|
-
schema: SAMPLE_SCHEMA,
|
|
246
263
|
capabilities: { mode: "data", previews: [] }
|
|
247
|
-
},
|
|
248
|
-
logic: {
|
|
249
|
-
label: "Logic (variants + conditionals)",
|
|
250
|
-
description: "Shows every logic construct: a oneOf variant, if/then/else conditionals, a const field, and a nullable optional.",
|
|
251
|
-
schema: LOGIC_SCHEMA,
|
|
252
|
-
capabilities: { previews: ["form", "table", "json", "capabilities"] }
|
|
253
264
|
}
|
|
254
265
|
};
|
|
255
266
|
function PlaySchemaDesigner() {
|
|
267
|
+
const [exampleKey, setExampleKey] = useState("medium");
|
|
256
268
|
const [profileKey, setProfileKey] = useState("full");
|
|
257
269
|
const profile = PROFILES[profileKey];
|
|
258
|
-
const [schema, setSchema] = useState(
|
|
270
|
+
const [schema, setSchema] = useState(EXAMPLES.medium.schema);
|
|
259
271
|
const [uiSchema, setUiSchema] = useState({});
|
|
272
|
+
const load = (example, key) => {
|
|
273
|
+
setSchema(PROFILES[key].schema ?? EXAMPLES[example].schema);
|
|
274
|
+
setUiSchema({});
|
|
275
|
+
};
|
|
276
|
+
const selectExample = (key) => {
|
|
277
|
+
setExampleKey(key);
|
|
278
|
+
load(key, profileKey);
|
|
279
|
+
};
|
|
260
280
|
const selectProfile = (key) => {
|
|
281
|
+
const reload = !!PROFILES[key].schema || !!profile.schema;
|
|
261
282
|
setProfileKey(key);
|
|
262
|
-
|
|
263
|
-
setUiSchema({});
|
|
283
|
+
if (reload) load(exampleKey, key);
|
|
264
284
|
};
|
|
265
285
|
return /* @__PURE__ */ jsxs("div", { className: "w-full flex flex-col gap-3 h-[calc(100vh-8rem)]", children: [
|
|
266
286
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
267
287
|
/* @__PURE__ */ jsx("h1", { children: "Schema Designer" }),
|
|
268
288
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-3", children: "Visually author a JSON Schema and its UI presentation hints. Edits flow through onChange as a valid schema + uiSchema." })
|
|
269
289
|
] }),
|
|
270
|
-
/* @__PURE__ */
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
id: "capability-profile",
|
|
283
|
-
name: "profile",
|
|
284
|
-
value: profileKey,
|
|
285
|
-
options: Object.keys(PROFILES).map((k) => ({
|
|
286
|
-
value: k,
|
|
287
|
-
label: PROFILES[k].label
|
|
288
|
-
})),
|
|
289
|
-
onChange: (v) => selectProfile(v ?? "full"),
|
|
290
|
-
clearable: false
|
|
291
|
-
}
|
|
292
|
-
) }),
|
|
293
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: profile.description })
|
|
294
|
-
] }),
|
|
290
|
+
/* @__PURE__ */ jsx(
|
|
291
|
+
DesignerControls,
|
|
292
|
+
{
|
|
293
|
+
examples: EXAMPLES,
|
|
294
|
+
example: exampleKey,
|
|
295
|
+
onExample: selectExample,
|
|
296
|
+
exampleLocked: profile.schemaLabel,
|
|
297
|
+
profiles: PROFILES,
|
|
298
|
+
profile: profileKey,
|
|
299
|
+
onProfile: selectProfile
|
|
300
|
+
}
|
|
301
|
+
),
|
|
295
302
|
/* @__PURE__ */ jsx("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsx(
|
|
296
303
|
SchemaDesigner,
|
|
297
304
|
{
|
|
@@ -304,7 +311,7 @@ function PlaySchemaDesigner() {
|
|
|
304
311
|
setUiSchema(nextUiSchema);
|
|
305
312
|
}
|
|
306
313
|
},
|
|
307
|
-
profileKey
|
|
314
|
+
`${exampleKey}-${profileKey}`
|
|
308
315
|
) })
|
|
309
316
|
] });
|
|
310
317
|
}
|
|
@@ -312,4 +319,4 @@ function PlaySchemaDesigner() {
|
|
|
312
319
|
export {
|
|
313
320
|
PlaySchemaDesigner
|
|
314
321
|
};
|
|
315
|
-
//# sourceMappingURL=chunk-
|
|
322
|
+
//# sourceMappingURL=chunk-EPCUUTBZ.js.map
|