@protobase/ui 0.19.8 → 0.19.10
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/dist/app/app.js +4 -4
- package/dist/app/create/create-offered.js +9 -0
- package/dist/app/create/create-page.js +4 -4
- package/dist/app/create/create-record-form.js +26 -62
- package/dist/app/create/create-route.js +29 -0
- package/dist/app/create/form.d.ts +30 -0
- package/dist/app/create/form.js +72 -0
- package/dist/app/custom-section.js +1 -1
- package/dist/app/displays/map-display.js +1 -1
- package/dist/app/displays/record-card.js +18 -4
- package/dist/app/displays/record-link.js +1 -1
- package/dist/app/displays/use-map-records.js +2 -2
- package/dist/app/embedded-list/embedded-columns.js +2 -2
- package/dist/app/embedded-list/embedded-list.js +5 -5
- package/dist/app/embedded-list/use-embedded-rows.js +2 -2
- package/dist/app/field-editor.js +21 -5
- package/dist/app/gallery/gallery-section.js +1 -1
- package/dist/app/gallery/photo-details.js +2 -2
- package/dist/app/list-page.js +18 -17
- package/dist/app/pages/blocks/card-row.js +2 -2
- package/dist/app/pages/blocks/field.js +2 -2
- package/dist/app/pages/blocks/link.js +1 -1
- package/dist/app/pages/blocks/modal-form.js +6 -6
- package/dist/app/pages/blocks/progress.js +1 -1
- package/dist/app/pages/blocks/record-card.js +2 -2
- package/dist/app/pages/blocks/record-row.js +1 -1
- package/dist/app/pages/blocks/show.js +2 -2
- package/dist/app/pages/blocks/stat.js +3 -3
- package/dist/app/pages/blocks/table.js +1 -1
- package/dist/app/pages/field-value.js +5 -2
- package/dist/app/pages/record-actions.js +2 -2
- package/dist/app/pages/use-run-action.js +2 -2
- package/dist/app/record-page.js +15 -11
- package/dist/app/record-row/record-row-body.js +2 -2
- package/dist/app/record-row/saved-record-row.js +1 -1
- package/dist/app/related-section.js +1 -1
- package/dist/app/searches/saved-search-rows.js +1 -1
- package/dist/app/searches/saved-search-section.js +2 -2
- package/dist/app/searches/saved-searches.js +2 -2
- package/dist/app/searches/search-controls.js +1 -1
- package/dist/app/searches/search-name-dialog.js +1 -1
- package/dist/app/searches/update-search-dialog.js +2 -2
- package/dist/app/searches/use-filter-chips.js +1 -1
- package/dist/app/searches/use-save-search.js +2 -2
- package/dist/app/searches/use-saved-searches.js +1 -1
- package/dist/app/searches/use-search-row.js +1 -1
- package/dist/app/sensitive-field.js +1 -1
- package/dist/app/use-app-address.js +1 -1
- package/dist/app/value-badge.js +1 -1
- package/dist/auth/sign-in-prompt.js +1 -1
- package/dist/data-grid/cells.js +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +10 -2
- package/dist/live/columns-from-model.js +3 -0
- package/dist/live/grid-loader.js +1 -1
- package/dist/live/use-filter-config.js +1 -1
- package/dist/markdown/markdown-content.js +18 -0
- package/dist/markdown/markdown-editor.js +46 -0
- package/dist/markdown/markdown-excerpt.js +36 -0
- package/dist/markdown/markdown-hint.js +5 -0
- package/dist/markdown/markdown-html.js +59 -0
- package/dist/markdown/markdown.js +15 -0
- package/dist/package.js +1 -1
- package/dist/primitives/choices.d.ts +22 -0
- package/dist/primitives/choices.js +33 -0
- package/dist/primitives/dialog.d.ts +15 -0
- package/dist/primitives/menu-select.d.ts +14 -0
- package/dist/primitives/segmented.d.ts +23 -0
- package/dist/primitives/textarea.d.ts +9 -0
- package/dist/record-view/field.d.ts +27 -0
- package/dist/record-view/section.d.ts +10 -0
- package/dist/shell/assets/app-GKl91FLS.js +69 -0
- package/dist/shell/assets/{index-cMmFPuUQ.js → index-BB2BN-6s.js} +1 -1
- package/dist/shell/assets/index-DxV5Rp_F.css +2 -0
- package/dist/shell/assets/{maplibre-9XYrB9k6.js → maplibre-DHotMteL.js} +2 -2
- package/dist/shell/assets/markdown-content-C4zE1qZp.js +67 -0
- package/dist/shell/assets/{record-map-OBtKCiUB.js → record-map-BBbVY6vn.js} +1 -1
- package/dist/shell/assets/{records-map-C4oMPL5C.js → records-map-ur6HR-I5.js} +1 -1
- package/dist/shell/assets/shared-protobase-ui-D7kkYiTL.js +1 -0
- package/dist/shell/index.html +4 -4
- package/dist/shell/protobase.shell.json +1 -1
- package/package.json +6 -4
- package/dist/shell/assets/app-D8i5r_6U.js +0 -68
- package/dist/shell/assets/index-Cuulz26c.css +0 -2
- package/dist/shell/assets/shared-protobase-ui-CN1HmyDa.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AppLink } from "../../use-app-address.js";
|
|
2
1
|
import { useLayoutRecord } from "../record-scope.js";
|
|
2
|
+
import { AppLink } from "../../use-app-address.js";
|
|
3
3
|
import { propsOf } from "./block-props.js";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
import { appPath } from "@protobase/schema";
|
|
@@ -4,15 +4,15 @@ import { useClient } from "../../../data/api-provider.js";
|
|
|
4
4
|
import { humanize } from "../../../live/naming.js";
|
|
5
5
|
import { useToast } from "../../../toasts/toast-provider.js";
|
|
6
6
|
import { useAdminMeta, usePermissions } from "../../meta-gate.js";
|
|
7
|
-
import {
|
|
8
|
-
import { ErrorBanner } from "../../error-banner.js";
|
|
9
|
-
import { FieldEditor } from "../../field-editor.js";
|
|
7
|
+
import { useLayoutRecord } from "../record-scope.js";
|
|
10
8
|
import { can } from "../../permissions.js";
|
|
11
|
-
import { Field } from "../../../record-view/field.js";
|
|
12
|
-
import { createBody, isChosen } from "../../create/create-values.js";
|
|
13
9
|
import { useFirstRecord, useRefreshResource } from "../use-layout-data.js";
|
|
14
|
-
import { useLayoutRecord } from "../record-scope.js";
|
|
15
10
|
import { propsOf } from "./block-props.js";
|
|
11
|
+
import { ErrorBanner } from "../../error-banner.js";
|
|
12
|
+
import { differs, toDraft, toPatchValue } from "../../../live/field-values.js";
|
|
13
|
+
import { Field } from "../../../record-view/field.js";
|
|
14
|
+
import { createBody, isChosen } from "../../create/create-values.js";
|
|
15
|
+
import { FieldEditor } from "../../field-editor.js";
|
|
16
16
|
import { useState } from "react";
|
|
17
17
|
import { isApiError } from "@protobase/client";
|
|
18
18
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Skeleton } from "../../../primitives/skeleton.js";
|
|
2
|
-
import { usePathValue } from "../use-path-value.js";
|
|
3
2
|
import { useLayoutRecord } from "../record-scope.js";
|
|
4
3
|
import { propsOf } from "./block-props.js";
|
|
4
|
+
import { usePathValue } from "../use-path-value.js";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/app/pages/blocks/progress.tsx
|
|
7
7
|
/** A number as given, or the number in a field of the record around it. */
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Skeleton } from "../../../primitives/skeleton.js";
|
|
2
2
|
import { useAdminMeta } from "../../meta-gate.js";
|
|
3
|
-
import { ErrorBanner } from "../../error-banner.js";
|
|
4
|
-
import { useFirstRecord } from "../use-layout-data.js";
|
|
5
3
|
import { RecordScope } from "../record-scope.js";
|
|
4
|
+
import { useFirstRecord } from "../use-layout-data.js";
|
|
6
5
|
import { propsOf } from "./block-props.js";
|
|
7
6
|
import { CardFrame, Quiet } from "./card-frame.js";
|
|
7
|
+
import { ErrorBanner } from "../../error-banner.js";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/app/pages/blocks/record-card.tsx
|
|
10
10
|
const LoadedRecordCard = ({ model, filter, sort, recordKey, title, description, empty, actions, children }) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useAdminMeta } from "../../meta-gate.js";
|
|
2
|
-
import { RecordRowBody } from "../../record-row/record-row-body.js";
|
|
3
2
|
import { propsOf } from "./block-props.js";
|
|
4
3
|
import { CardFrame } from "./card-frame.js";
|
|
4
|
+
import { RecordRowBody } from "../../record-row/record-row-body.js";
|
|
5
5
|
import { SavedRecordRow } from "../../record-row/saved-record-row.js";
|
|
6
6
|
import { SavedSearchRows } from "../../searches/saved-search-rows.js";
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useClient } from "../../../data/api-provider.js";
|
|
2
2
|
import { useAdminMeta } from "../../meta-gate.js";
|
|
3
|
-
import { countQuery } from "../use-layout-data.js";
|
|
4
|
-
import { usePathValues } from "../use-path-value.js";
|
|
5
3
|
import { useLayoutRecord } from "../record-scope.js";
|
|
4
|
+
import { countQuery } from "../use-layout-data.js";
|
|
6
5
|
import { propsOf } from "./block-props.js";
|
|
6
|
+
import { usePathValues } from "../use-path-value.js";
|
|
7
7
|
import { useMemo } from "react";
|
|
8
8
|
import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
|
|
9
9
|
import { useQueries } from "@tanstack/react-query";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Skeleton } from "../../../primitives/skeleton.js";
|
|
2
2
|
import { useAdminMeta } from "../../meta-gate.js";
|
|
3
|
+
import { useLayoutRecord } from "../record-scope.js";
|
|
3
4
|
import { AppLink } from "../../use-app-address.js";
|
|
4
5
|
import { useCount } from "../use-layout-data.js";
|
|
5
|
-
import { FieldValue } from "../field-value.js";
|
|
6
|
-
import { usePathValue } from "../use-path-value.js";
|
|
7
|
-
import { useLayoutRecord } from "../record-scope.js";
|
|
8
6
|
import { propsOf } from "./block-props.js";
|
|
9
7
|
import { CardFrame } from "./card-frame.js";
|
|
8
|
+
import { FieldValue } from "../field-value.js";
|
|
9
|
+
import { usePathValue } from "../use-path-value.js";
|
|
10
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
11
|
//#region src/app/pages/blocks/stat.tsx
|
|
12
12
|
const big = "text-2xl font-semibold tracking-tight tabular-nums";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useAdminMeta } from "../../meta-gate.js";
|
|
2
|
-
import { EmbeddedDisplaySwitch, EmbeddedList } from "../../embedded-list/embedded-list.js";
|
|
3
2
|
import { propsOf } from "./block-props.js";
|
|
4
3
|
import { CardFrame } from "./card-frame.js";
|
|
4
|
+
import { EmbeddedDisplaySwitch, EmbeddedList } from "../../embedded-list/embedded-list.js";
|
|
5
5
|
import { useEmbeddedDisplay } from "../../embedded-list/use-embedded-display.js";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/app/pages/blocks/table.tsx
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { cn } from "../../lib/cn.js";
|
|
2
2
|
import { keys } from "../../data/query-keys.js";
|
|
3
3
|
import { useClient } from "../../data/api-provider.js";
|
|
4
|
-
import {
|
|
4
|
+
import { useAdminMeta } from "../meta-gate.js";
|
|
5
5
|
import { fileShown, shownImage } from "../../live/file-values.js";
|
|
6
6
|
import { displayValue } from "../../live/display-value.js";
|
|
7
|
-
import { useAdminMeta } from "../meta-gate.js";
|
|
8
7
|
import { AppLink } from "../use-app-address.js";
|
|
9
8
|
import { FileImage } from "../../live/file-image.js";
|
|
9
|
+
import { fetchLabels } from "../../live/relation-labels.js";
|
|
10
10
|
import { useShownWidget } from "../field-types/shown-widget.js";
|
|
11
11
|
import { WidgetPart } from "../field-types/widget-part.js";
|
|
12
|
+
import { isMarkdown } from "../../markdown/markdown-hint.js";
|
|
12
13
|
import { ValueBadge } from "../value-badge.js";
|
|
14
|
+
import { Markdown } from "../../markdown/markdown.js";
|
|
13
15
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
16
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
15
17
|
//#region src/app/pages/field-value.tsx
|
|
@@ -70,6 +72,7 @@ const BuiltInValue = ({ model, field, value, format, relationLabel }) => {
|
|
|
70
72
|
})]
|
|
71
73
|
});
|
|
72
74
|
}
|
|
75
|
+
if (isMarkdown(field, hints)) return /* @__PURE__ */ jsx(Markdown, { source: String(value) });
|
|
73
76
|
const text = displayValue(field, value, hints);
|
|
74
77
|
if (field.type === "enum" || hints.format === "badge") return /* @__PURE__ */ jsx(ValueBadge, {
|
|
75
78
|
value,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { AppLink, useAppAddress } from "../use-app-address.js";
|
|
2
|
-
import { ActionRail } from "../../record-view/action-rail.js";
|
|
3
1
|
import { ConfirmAction } from "./confirm-action.js";
|
|
2
|
+
import { AppLink, useAppAddress } from "../use-app-address.js";
|
|
4
3
|
import { useActionRunner } from "./use-run-action.js";
|
|
4
|
+
import { ActionRail } from "../../record-view/action-rail.js";
|
|
5
5
|
import { actionIcon } from "../action-icon.js";
|
|
6
6
|
import { useState } from "react";
|
|
7
7
|
import { Pencil, Trash2 } from "lucide-react";
|
|
@@ -2,10 +2,10 @@ import { useClient, useResourceClient } from "../../data/api-provider.js";
|
|
|
2
2
|
import { useToast } from "../../toasts/toast-provider.js";
|
|
3
3
|
import { useProjectUi } from "./project-ui.js";
|
|
4
4
|
import { useAdminMeta, usePermissions } from "../meta-gate.js";
|
|
5
|
-
import { useAppAddress } from "../use-app-address.js";
|
|
6
5
|
import { can } from "../permissions.js";
|
|
7
|
-
import {
|
|
6
|
+
import { useAppAddress } from "../use-app-address.js";
|
|
8
7
|
import { actionFor, linkTarget, openLink } from "./action-href.js";
|
|
8
|
+
import { useRefreshResource } from "./use-layout-data.js";
|
|
9
9
|
import { useState } from "react";
|
|
10
10
|
import { fillAddress } from "@protobase/schema/internal";
|
|
11
11
|
//#region src/app/pages/use-run-action.ts
|
package/dist/app/record-page.js
CHANGED
|
@@ -9,27 +9,29 @@ import { useRecord } from "../data/use-record.js";
|
|
|
9
9
|
import { recordTitle } from "../live/model-helpers.js";
|
|
10
10
|
import { humanize } from "../live/naming.js";
|
|
11
11
|
import { useProjectUi } from "./pages/project-ui.js";
|
|
12
|
+
import { Notice, useAdminMeta, usePermissions } from "./meta-gate.js";
|
|
13
|
+
import { can, fieldAccess } from "./permissions.js";
|
|
12
14
|
import { displayValue } from "../live/display-value.js";
|
|
13
15
|
import { filledFields } from "./filled-fields.js";
|
|
14
|
-
import { Notice, useAdminMeta, usePermissions } from "./meta-gate.js";
|
|
15
16
|
import { AppLink, useAppAddress } from "./use-app-address.js";
|
|
16
17
|
import { ErrorBanner } from "./error-banner.js";
|
|
17
18
|
import { shownWidget } from "./field-types/shown-widget.js";
|
|
18
19
|
import { WidgetPart } from "./field-types/widget-part.js";
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
20
|
+
import { isMarkdown } from "../markdown/markdown-hint.js";
|
|
21
|
+
import { toneFor } from "../live/columns-from-model.js";
|
|
22
|
+
import { ValueBadge } from "./value-badge.js";
|
|
23
|
+
import { Markdown } from "../markdown/markdown.js";
|
|
24
|
+
import { FieldValue } from "./pages/field-value.js";
|
|
21
25
|
import { Field } from "../record-view/field.js";
|
|
22
26
|
import { Section } from "../record-view/section.js";
|
|
23
27
|
import { MetadataCard, RelatedRecords, SidebarCard } from "../record-view/record-sidebar.js";
|
|
24
28
|
import { RecordHeader } from "../record-view/record-header.js";
|
|
25
29
|
import { SpecTable } from "../record-view/spec-table.js";
|
|
26
30
|
import { KeyFacts } from "../record-view/key-facts.js";
|
|
27
|
-
import {
|
|
31
|
+
import { FieldEditor } from "./field-editor.js";
|
|
32
|
+
import { namedIcon } from "./named-icon.js";
|
|
28
33
|
import { useDeleteFlow } from "./delete/use-delete-flow.js";
|
|
29
34
|
import { useRestore } from "./delete/use-restore.js";
|
|
30
|
-
import { namedIcon } from "./named-icon.js";
|
|
31
|
-
import { ValueBadge } from "./value-badge.js";
|
|
32
|
-
import { FieldValue } from "./pages/field-value.js";
|
|
33
35
|
import { auditField } from "../live/audit-fields.js";
|
|
34
36
|
import { CustomSection } from "./custom-section.js";
|
|
35
37
|
import { MapSection } from "./map/map-section.js";
|
|
@@ -164,7 +166,7 @@ const LoadedRecord = ({ model, recordKey, stored }) => {
|
|
|
164
166
|
label: hint(name)?.label ?? humanize(name),
|
|
165
167
|
help: fieldHelp(hint(name), view, editing),
|
|
166
168
|
error: editor.errors[name],
|
|
167
|
-
wide: Boolean(hint(name)?.multiline),
|
|
169
|
+
wide: Boolean(hint(name)?.multiline || hint(name)?.markdown),
|
|
168
170
|
conflict: conflict === void 0 ? void 0 : {
|
|
169
171
|
user: {
|
|
170
172
|
name: "Someone else",
|
|
@@ -211,7 +213,7 @@ const LoadedRecord = ({ model, recordKey, stored }) => {
|
|
|
211
213
|
return {
|
|
212
214
|
label: hint(name)?.label ?? humanize(name),
|
|
213
215
|
help: fieldHelp(hint(name), view, editing),
|
|
214
|
-
wide: Boolean(hint(name)?.multiline),
|
|
216
|
+
wide: Boolean(hint(name)?.multiline || hint(name)?.markdown),
|
|
215
217
|
value
|
|
216
218
|
};
|
|
217
219
|
};
|
|
@@ -222,11 +224,13 @@ const LoadedRecord = ({ model, recordKey, stored }) => {
|
|
|
222
224
|
const field = model.fields[name];
|
|
223
225
|
if (!field || !visible(name)) return [];
|
|
224
226
|
const text = displayValue(field, stored.record[name], hint(name));
|
|
227
|
+
const value = stored.record[name];
|
|
228
|
+
const markdown = isMarkdown(field, hint(name)) && typeof value === "string" && value !== "";
|
|
225
229
|
const builtIn = field.type === "enum" ? /* @__PURE__ */ jsx(ValueBadge, {
|
|
226
|
-
value
|
|
230
|
+
value,
|
|
227
231
|
hints: hint(name),
|
|
228
232
|
children: text
|
|
229
|
-
}) : /* @__PURE__ */ jsx("strong", {
|
|
233
|
+
}) : markdown ? /* @__PURE__ */ jsx(Markdown, { source: value }) : /* @__PURE__ */ jsx("strong", {
|
|
230
234
|
className: hint(name)?.multiline ? "whitespace-pre-line break-words" : void 0,
|
|
231
235
|
children: text
|
|
232
236
|
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { useIsXs } from "../../lib/use-media-query.js";
|
|
2
2
|
import { Skeleton } from "../../primitives/skeleton.js";
|
|
3
3
|
import { humanize } from "../../live/naming.js";
|
|
4
|
+
import { useAdminMeta } from "../meta-gate.js";
|
|
4
5
|
import { displaysOf, loadedFields } from "../displays/list-displays.js";
|
|
5
6
|
import { defaultOrderBy } from "../list-order.js";
|
|
6
|
-
import { useAdminMeta } from "../meta-gate.js";
|
|
7
7
|
import { AppLink } from "../use-app-address.js";
|
|
8
8
|
import { ErrorBanner } from "../error-banner.js";
|
|
9
9
|
import { useLiveRows } from "../../live/use-live-rows.js";
|
|
10
|
-
import { FilterChipList } from "../searches/filter-chip-list.js";
|
|
11
10
|
import { viewAllAddress } from "../embedded-list/embedded-display.js";
|
|
11
|
+
import { FilterChipList } from "../searches/filter-chip-list.js";
|
|
12
12
|
import { useFilterChips } from "../searches/use-filter-chips.js";
|
|
13
13
|
import { RecordRow } from "./record-row.js";
|
|
14
14
|
import { useMemo } from "react";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Skeleton } from "../../primitives/skeleton.js";
|
|
2
2
|
import { humanize } from "../../live/naming.js";
|
|
3
|
-
import { listedResource } from "../current-address.js";
|
|
4
3
|
import { useAdminMeta } from "../meta-gate.js";
|
|
4
|
+
import { listedResource } from "../current-address.js";
|
|
5
5
|
import { ErrorBanner } from "../error-banner.js";
|
|
6
6
|
import { savedScope } from "../saved/saved-records.js";
|
|
7
7
|
import { useSavedRecords } from "../saved/use-saved-records.js";
|
|
@@ -3,8 +3,8 @@ import { keys } from "../data/query-keys.js";
|
|
|
3
3
|
import { useClient } from "../data/api-provider.js";
|
|
4
4
|
import { useAdminMeta } from "./meta-gate.js";
|
|
5
5
|
import { ErrorBanner } from "./error-banner.js";
|
|
6
|
-
import { Section } from "../record-view/section.js";
|
|
7
6
|
import { listColumnNames } from "../live/columns-from-model.js";
|
|
7
|
+
import { Section } from "../record-view/section.js";
|
|
8
8
|
import { EmbeddedDisplaySwitch, EmbeddedList } from "./embedded-list/embedded-list.js";
|
|
9
9
|
import { useEmbeddedDisplay } from "./embedded-list/use-embedded-display.js";
|
|
10
10
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -5,8 +5,8 @@ import { useAdminMeta } from "../meta-gate.js";
|
|
|
5
5
|
import { AppLink } from "../use-app-address.js";
|
|
6
6
|
import { ErrorBanner } from "../error-banner.js";
|
|
7
7
|
import { InlineFilterChips } from "./filter-chip-list.js";
|
|
8
|
-
import { useSavedSearches } from "./use-saved-searches.js";
|
|
9
8
|
import { RecordRowBody } from "../record-row/record-row-body.js";
|
|
9
|
+
import { useSavedSearches } from "./use-saved-searches.js";
|
|
10
10
|
import { useSearchRow } from "./use-search-row.js";
|
|
11
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
import { encodeKey } from "@protobase/schema/internal";
|
|
@@ -5,10 +5,10 @@ import { useToast } from "../../toasts/toast-provider.js";
|
|
|
5
5
|
import { AppLink } from "../use-app-address.js";
|
|
6
6
|
import { useRefreshResource } from "../pages/use-layout-data.js";
|
|
7
7
|
import { InlineFilterChips } from "./filter-chip-list.js";
|
|
8
|
-
import { SearchNameDialog } from "./search-name-dialog.js";
|
|
9
8
|
import { RecordRowBody } from "../record-row/record-row-body.js";
|
|
10
|
-
import { SearchControls } from "./search-controls.js";
|
|
11
9
|
import { useSearchRow } from "./use-search-row.js";
|
|
10
|
+
import { SearchNameDialog } from "./search-name-dialog.js";
|
|
11
|
+
import { SearchControls } from "./search-controls.js";
|
|
12
12
|
import { useState } from "react";
|
|
13
13
|
import { Pencil, Trash2 } from "lucide-react";
|
|
14
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -3,11 +3,11 @@ import { PageHeader } from "../../app-shell/page-header.js";
|
|
|
3
3
|
import { recordKey } from "../../live/model-helpers.js";
|
|
4
4
|
import { humanize } from "../../live/naming.js";
|
|
5
5
|
import { Notice, useAdminMeta, usePermissions } from "../meta-gate.js";
|
|
6
|
+
import { can } from "../permissions.js";
|
|
6
7
|
import { AppLink } from "../use-app-address.js";
|
|
7
8
|
import { ErrorBanner } from "../error-banner.js";
|
|
8
|
-
import { can } from "../permissions.js";
|
|
9
|
-
import { useDeleteFlow } from "../delete/use-delete-flow.js";
|
|
10
9
|
import { useSavedSearches } from "./use-saved-searches.js";
|
|
10
|
+
import { useDeleteFlow } from "../delete/use-delete-flow.js";
|
|
11
11
|
import { SavedSearchSection } from "./saved-search-section.js";
|
|
12
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
13
|
import { encodeKey } from "@protobase/schema/internal";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useClient } from "../../data/api-provider.js";
|
|
2
2
|
import { humanize } from "../../live/naming.js";
|
|
3
3
|
import { useToast } from "../../toasts/toast-provider.js";
|
|
4
|
-
import { Switch } from "../../primitives/switch.js";
|
|
5
4
|
import { useRefreshResource } from "../pages/use-layout-data.js";
|
|
5
|
+
import { Switch } from "../../primitives/switch.js";
|
|
6
6
|
import { useId } from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { useMutation } from "@tanstack/react-query";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Input } from "../../primitives/input.js";
|
|
2
2
|
import { Button } from "../../primitives/button.js";
|
|
3
|
-
import { ResponsiveDialog } from "../../primitives/responsive-dialog.js";
|
|
4
3
|
import { FilterChipList } from "./filter-chip-list.js";
|
|
4
|
+
import { ResponsiveDialog } from "../../primitives/responsive-dialog.js";
|
|
5
5
|
import { useId, useState } from "react";
|
|
6
6
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/app/searches/search-name-dialog.tsx
|
|
@@ -3,11 +3,11 @@ import { Button } from "../../primitives/button.js";
|
|
|
3
3
|
import { useClient } from "../../data/api-provider.js";
|
|
4
4
|
import { humanize } from "../../live/naming.js";
|
|
5
5
|
import { defaultOrderBy } from "../list-order.js";
|
|
6
|
-
import { ResponsiveDialog } from "../../primitives/responsive-dialog.js";
|
|
7
6
|
import { countQuery } from "../pages/use-layout-data.js";
|
|
7
|
+
import { useFilterChips } from "./use-filter-chips.js";
|
|
8
|
+
import { ResponsiveDialog } from "../../primitives/responsive-dialog.js";
|
|
8
9
|
import { EmbeddedList } from "../embedded-list/embedded-list.js";
|
|
9
10
|
import { addedFilter, filterChanges, netChange, removedFilter } from "./search-diff.js";
|
|
10
|
-
import { useFilterChips } from "./use-filter-chips.js";
|
|
11
11
|
import { useMemo } from "react";
|
|
12
12
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
13
13
|
import { useQuery } from "@tanstack/react-query";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { keys } from "../../data/query-keys.js";
|
|
2
2
|
import { useClient } from "../../data/api-provider.js";
|
|
3
|
-
import { fetchLabels } from "../../live/relation-labels.js";
|
|
4
3
|
import { useAdminMeta } from "../meta-gate.js";
|
|
4
|
+
import { fetchLabels } from "../../live/relation-labels.js";
|
|
5
5
|
import { chosenRelations, filterChips } from "./saved-search.js";
|
|
6
6
|
import { useQueries, useQueryClient } from "@tanstack/react-query";
|
|
7
7
|
//#region src/app/searches/use-filter-chips.ts
|
|
@@ -3,11 +3,11 @@ import { recordKey } from "../../live/model-helpers.js";
|
|
|
3
3
|
import { humanize } from "../../live/naming.js";
|
|
4
4
|
import { useToast } from "../../toasts/toast-provider.js";
|
|
5
5
|
import { useAdminMeta } from "../meta-gate.js";
|
|
6
|
-
import { useAppAddress } from "../use-app-address.js";
|
|
7
6
|
import { can } from "../permissions.js";
|
|
7
|
+
import { useAppAddress } from "../use-app-address.js";
|
|
8
8
|
import { useRefreshResource } from "../pages/use-layout-data.js";
|
|
9
|
-
import { useOpenedSearch } from "./use-opened-search.js";
|
|
10
9
|
import { useSavedSearches } from "./use-saved-searches.js";
|
|
10
|
+
import { useOpenedSearch } from "./use-opened-search.js";
|
|
11
11
|
import { useMutation } from "@tanstack/react-query";
|
|
12
12
|
import { encodeKey } from "@protobase/schema/internal";
|
|
13
13
|
//#region src/app/searches/use-save-search.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { keys } from "../../data/query-keys.js";
|
|
2
2
|
import { useClient } from "../../data/api-provider.js";
|
|
3
|
-
import { defaultOrderBy } from "../list-order.js";
|
|
4
3
|
import { useAdminMeta } from "../meta-gate.js";
|
|
4
|
+
import { defaultOrderBy } from "../list-order.js";
|
|
5
5
|
import { useQuery } from "@tanstack/react-query";
|
|
6
6
|
//#region src/app/searches/use-saved-searches.ts
|
|
7
7
|
/** Where the user's saved searches of `resource` are cached; a list key, so a write to the resource refreshes it. */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useClient } from "../../data/api-provider.js";
|
|
2
2
|
import { humanize } from "../../live/naming.js";
|
|
3
3
|
import { countQuery, useRefreshResource } from "../pages/use-layout-data.js";
|
|
4
|
-
import { isUnseen, unseenFilter } from "./saved-search.js";
|
|
5
4
|
import { chipsText } from "./filter-chip-list.js";
|
|
5
|
+
import { isUnseen, unseenFilter } from "./saved-search.js";
|
|
6
6
|
import { useFilterChips } from "./use-filter-chips.js";
|
|
7
7
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
8
8
|
//#region src/app/searches/use-search-row.ts
|
|
@@ -3,8 +3,8 @@ import { Input } from "../primitives/input.js";
|
|
|
3
3
|
import { Button } from "../primitives/button.js";
|
|
4
4
|
import { humanize } from "../live/naming.js";
|
|
5
5
|
import { displayValue } from "../live/display-value.js";
|
|
6
|
-
import { toDraft } from "../live/field-values.js";
|
|
7
6
|
import { ErrorBanner } from "./error-banner.js";
|
|
7
|
+
import { toDraft } from "../live/field-values.js";
|
|
8
8
|
import { useState } from "react";
|
|
9
9
|
import { Eye, EyeOff } from "lucide-react";
|
|
10
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useIsXs } from "../lib/use-media-query.js";
|
|
2
2
|
import { Link, useRouter } from "./router.js";
|
|
3
|
-
import { changedList, currentAddress, listDefaults, listedResource } from "./current-address.js";
|
|
4
3
|
import { useAdminMeta } from "./meta-gate.js";
|
|
4
|
+
import { changedList, currentAddress, listDefaults, listedResource } from "./current-address.js";
|
|
5
5
|
import { useCallback, useMemo } from "react";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
import { appPath, readAppPath } from "@protobase/schema";
|
package/dist/app/value-badge.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Badge } from "../primitives/badge.js";
|
|
2
|
-
import { valueColor } from "../live/value-color.js";
|
|
3
2
|
import { toneFor } from "../live/columns-from-model.js";
|
|
3
|
+
import { valueColor } from "../live/value-color.js";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/app/value-badge.tsx
|
|
6
6
|
/** A stored value as a badge: filled with the colour the view gives it and in its badge shape, else in its tone. */
|
|
@@ -2,8 +2,8 @@ import { RouteLink } from "../primitives/route-link.js";
|
|
|
2
2
|
import { useAuth } from "./auth-provider.js";
|
|
3
3
|
import { Button, buttonClass } from "../primitives/button.js";
|
|
4
4
|
import { useSignInAddress } from "./use-sign-in-address.js";
|
|
5
|
-
import { ResponsiveDialog } from "../primitives/responsive-dialog.js";
|
|
6
5
|
import { namedIcon } from "../app/named-icon.js";
|
|
6
|
+
import { ResponsiveDialog } from "../primitives/responsive-dialog.js";
|
|
7
7
|
import { useId } from "react";
|
|
8
8
|
import { Check, LogIn } from "lucide-react";
|
|
9
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
package/dist/data-grid/cells.js
CHANGED
|
@@ -6,8 +6,8 @@ import { formatInt, formatPercent, formatSigned } from "../format/number.js";
|
|
|
6
6
|
import { formatDate, formatDateTime } from "../format/date.js";
|
|
7
7
|
import { fileShown, shownImage } from "../live/file-values.js";
|
|
8
8
|
import { FileImage } from "../live/file-image.js";
|
|
9
|
-
import { userById } from "../mocks/users.js";
|
|
10
9
|
import { valueColor } from "../live/value-color.js";
|
|
10
|
+
import { userById } from "../mocks/users.js";
|
|
11
11
|
import { Check, Paperclip } from "lucide-react";
|
|
12
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
13
|
import { enumLabel } from "@protobase/schema";
|
package/dist/index.d.ts
CHANGED
|
@@ -48,5 +48,13 @@ import { CodeForm, CodeFormProps } from "./auth/code-form.js";
|
|
|
48
48
|
import { ResendCodeButton, ResendCodeButtonProps } from "./auth/resend-code-button.js";
|
|
49
49
|
import { Button, ButtonProps, buttonClass } from "./primitives/button.js";
|
|
50
50
|
import { Input, InputProps } from "./primitives/input.js";
|
|
51
|
+
import { Textarea, TextareaProps } from "./primitives/textarea.js";
|
|
52
|
+
import { Segmented, SegmentedOption, SegmentedProps } from "./primitives/segmented.js";
|
|
53
|
+
import { MenuSelect, MenuSelectProps } from "./primitives/menu-select.js";
|
|
54
|
+
import { ChoiceOption, Choices, ChoicesProps } from "./primitives/choices.js";
|
|
55
|
+
import { Dialog, DialogProps } from "./primitives/dialog.js";
|
|
56
|
+
import { Field, FieldProps } from "./record-view/field.js";
|
|
57
|
+
import { Section } from "./record-view/section.js";
|
|
58
|
+
import { Form, FormProps } from "./app/create/form.js";
|
|
51
59
|
import { Spinner } from "./primitives/spinner.js";
|
|
52
|
-
export { ActionCard, type ActionCardProps, type ActionContext, type ActionHandler, ApiProvider, type ApiProviderProps, App, AppLink, type AppProps, AssistantDock, type AssistantDockProps, AuthLayout, type AuthLayoutProps, type BackendData, type BackendRefresh, type BeforeSignInProps, Button, type ButtonProps, type CardAction, type CardTone, ChatMessage, ChatThread, type ChatThreadProps, CodeForm, type CodeFormProps, CompactTable, type CompactTableProps, Composer, type ComposerProps, type CurrentAddress, type DiffLine, DiffView, type DiffViewProps, FieldList, type FieldWidget, type FieldWidgetEditorProps, type FieldWidgetProps, Input, type InputProps, type LayoutRecord, type ListAddress, type ListChange, type ListDisplay, type ListDisplayRow, LogoMark, type MetaData, OtpInput, type OtpInputProps, PartView, type PluginInfo, type ProjectUi, type RecordCardProps, RecordLink, ResendCodeButton, type ResendCodeButtonProps, ResponsiveDialog, type ResponsiveDialogProps, type ShellLogoProps, SidePanel, type SidePanelProps, SignInPrompt, type SignInPromptProps, Spinner, type Step, StepList, type StepState, buttonClass, definePlugin, defineUi, diffStats, isConflict, mergeUi, parseDiff, pluginApi, protobaseVersion, uiFromModule, useApiToken, useAppAddress, useAssistant, useAssistantClient, useBackendData, useClient, useFacets, useHistogram, useLayoutRecord, useList, useListDisplay, useMeta, usePlugin, useRecord, useResourceClient, useSeries, useUpdateRecord };
|
|
60
|
+
export { ActionCard, type ActionCardProps, type ActionContext, type ActionHandler, ApiProvider, type ApiProviderProps, App, AppLink, type AppProps, AssistantDock, type AssistantDockProps, AuthLayout, type AuthLayoutProps, type BackendData, type BackendRefresh, type BeforeSignInProps, Button, type ButtonProps, type CardAction, type CardTone, ChatMessage, ChatThread, type ChatThreadProps, type ChoiceOption, Choices, type ChoicesProps, CodeForm, type CodeFormProps, CompactTable, type CompactTableProps, Composer, type ComposerProps, type CurrentAddress, Dialog, type DialogProps, type DiffLine, DiffView, type DiffViewProps, Field, FieldList, type FieldProps, type FieldWidget, type FieldWidgetEditorProps, type FieldWidgetProps, Form, type FormProps, Input, type InputProps, type LayoutRecord, type ListAddress, type ListChange, type ListDisplay, type ListDisplayRow, LogoMark, MenuSelect, type MenuSelectProps, type MetaData, OtpInput, type OtpInputProps, PartView, type PluginInfo, type ProjectUi, type RecordCardProps, RecordLink, ResendCodeButton, type ResendCodeButtonProps, ResponsiveDialog, type ResponsiveDialogProps, Section, Segmented, type SegmentedOption, type SegmentedProps, type ShellLogoProps, SidePanel, type SidePanelProps, SignInPrompt, type SignInPromptProps, Spinner, type Step, StepList, type StepState, Textarea, type TextareaProps, buttonClass, definePlugin, defineUi, diffStats, isConflict, mergeUi, parseDiff, pluginApi, protobaseVersion, uiFromModule, useApiToken, useAppAddress, useAssistant, useAssistantClient, useBackendData, useClient, useFacets, useHistogram, useLayoutRecord, useList, useListDisplay, useMeta, usePlugin, useRecord, useResourceClient, useSeries, useUpdateRecord };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { LogoMark } from "./app-shell/logo.js";
|
|
2
|
+
import { Segmented } from "./primitives/segmented.js";
|
|
2
3
|
import { Input } from "./primitives/input.js";
|
|
3
4
|
import { Spinner } from "./primitives/spinner.js";
|
|
4
5
|
import { Button, buttonClass } from "./primitives/button.js";
|
|
6
|
+
import { Dialog } from "./primitives/dialog.js";
|
|
5
7
|
import { OtpInput } from "./primitives/otp-input.js";
|
|
6
8
|
import { ApiProvider, useClient, useResourceClient } from "./data/api-provider.js";
|
|
7
9
|
import { AuthLayout } from "./auth/auth-layout.js";
|
|
@@ -30,14 +32,20 @@ import { AssistantDock } from "./assistant-dock/assistant-dock.js";
|
|
|
30
32
|
import { useAssistant } from "./assistant-dock/use-assistant.js";
|
|
31
33
|
import { useAssistantClient } from "./assistant-dock/use-assistant-client.js";
|
|
32
34
|
import { useMeta } from "./data/use-meta.js";
|
|
35
|
+
import { useLayoutRecord } from "./app/pages/record-scope.js";
|
|
33
36
|
import { AppLink, useAppAddress } from "./app/use-app-address.js";
|
|
37
|
+
import { Field } from "./record-view/field.js";
|
|
38
|
+
import { Section } from "./record-view/section.js";
|
|
39
|
+
import { Textarea } from "./primitives/textarea.js";
|
|
34
40
|
import { ResponsiveDialog } from "./primitives/responsive-dialog.js";
|
|
35
41
|
import { SignInPrompt } from "./auth/sign-in-prompt.js";
|
|
36
42
|
import { useListDisplay } from "./app/displays/display-context.js";
|
|
43
|
+
import { MenuSelect } from "./primitives/menu-select.js";
|
|
44
|
+
import { Form } from "./app/create/form.js";
|
|
37
45
|
import { useFacets, useHistogram, useSeries } from "./data/use-aggregates.js";
|
|
38
|
-
import { useLayoutRecord } from "./app/pages/record-scope.js";
|
|
39
46
|
import { useList } from "./data/use-list.js";
|
|
40
47
|
import { isConflict, useUpdateRecord } from "./data/use-update-record.js";
|
|
41
48
|
import { App } from "./app/app.js";
|
|
42
49
|
import { RecordLink } from "./app/displays/record-link.js";
|
|
43
|
-
|
|
50
|
+
import { Choices } from "./primitives/choices.js";
|
|
51
|
+
export { ActionCard, ApiProvider, App, AppLink, AssistantDock, AuthLayout, Button, ChatMessage, ChatThread, Choices, CodeForm, CompactTable, Composer, Dialog, DiffView, Field, FieldList, Form, Input, LogoMark, MenuSelect, OtpInput, PartView, RecordLink, ResendCodeButton, ResponsiveDialog, Section, Segmented, SidePanel, SignInPrompt, Spinner, StepList, Textarea, buttonClass, definePlugin, defineUi, diffStats, isConflict, mergeUi, parseDiff, pluginApi, protobaseVersion, uiFromModule, useApiToken, useAppAddress, useAssistant, useAssistantClient, useBackendData, useClient, useFacets, useHistogram, useLayoutRecord, useList, useListDisplay, useMeta, usePlugin, useRecord, useResourceClient, useSeries, useUpdateRecord };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { humanize } from "./naming.js";
|
|
2
|
+
import { markdownExcerpt } from "../markdown/markdown-excerpt.js";
|
|
3
|
+
import { isMarkdown } from "../markdown/markdown-hint.js";
|
|
2
4
|
import { enumLabel } from "@protobase/schema";
|
|
3
5
|
//#region src/live/columns-from-model.ts
|
|
4
6
|
const tones = {
|
|
@@ -94,6 +96,7 @@ const columnsFromModel = (resource, view, highlight = [], names = listColumnName
|
|
|
94
96
|
value: (row) => row[name] == null ? null : currencyCents(row[name])
|
|
95
97
|
},
|
|
96
98
|
...(kind === "datetime" || kind === "date") && { value: (row) => row[name] == null ? null : Date.parse(String(row[name])) },
|
|
99
|
+
...isMarkdown(field, viewField) && { value: (row) => typeof row[name] === "string" ? markdownExcerpt(row[name]) : row[name] },
|
|
97
100
|
...(kind === "percent" || kind === "number" && field.type === "decimal") && { value: (row) => row[name] == null ? null : Number(row[name]) }
|
|
98
101
|
}];
|
|
99
102
|
});
|
package/dist/live/grid-loader.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { keys } from "../data/query-keys.js";
|
|
2
2
|
import { recordId } from "./model-helpers.js";
|
|
3
|
-
import { listLabels, withLabels } from "./relation-labels.js";
|
|
4
3
|
import { listPhotos, withPhotos } from "./row-photos.js";
|
|
4
|
+
import { listLabels, withLabels } from "./relation-labels.js";
|
|
5
5
|
//#region src/live/grid-loader.ts
|
|
6
6
|
const exactBelow = 5e3;
|
|
7
7
|
/**
|
|
@@ -5,9 +5,9 @@ import { humanize } from "./naming.js";
|
|
|
5
5
|
import { fetchLabels } from "./relation-labels.js";
|
|
6
6
|
import { setRange } from "../filter-panel/filter-state.js";
|
|
7
7
|
import { stateToText } from "./filter-string.js";
|
|
8
|
+
import { rangeFormat, rangeHistogram, widgetFields } from "./view-fields.js";
|
|
8
9
|
import { labelKeys, matchOptions } from "./reference-options.js";
|
|
9
10
|
import { useReferenceSearch } from "./use-reference-search.js";
|
|
10
|
-
import { rangeFormat, rangeHistogram, widgetFields } from "./view-fields.js";
|
|
11
11
|
import { useQueries, useQueryClient } from "@tanstack/react-query";
|
|
12
12
|
import { enumLabel } from "@protobase/schema";
|
|
13
13
|
//#region src/live/use-filter-config.ts
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { markdownHtml } from "./markdown-html.js";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import DOMPurify from "dompurify";
|
|
6
|
+
//#region src/markdown/markdown-content.tsx
|
|
7
|
+
const page = cn("break-words [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", "[&_p]:my-2 [&_ul]:my-2 [&_ol]:my-2 [&_pre]:my-2 [&_blockquote]:my-2 [&_table]:my-2 [&_hr]:my-3", "[&_h1]:mt-4 [&_h1]:mb-2 [&_h1]:text-lg [&_h1]:font-semibold [&_h2]:mt-4 [&_h2]:mb-2 [&_h2]:text-base [&_h2]:font-semibold", "[&_h3]:mt-3 [&_h3]:mb-1 [&_h3]:font-semibold [&_h4]:mt-3 [&_h4]:mb-1 [&_h4]:font-semibold [&_h5]:font-semibold [&_h6]:font-semibold", "[&_ul]:list-disc [&_ul]:pl-5 [&_ol]:list-decimal [&_ol]:pl-5 [&_li:has(>input)]:list-none [&_li>input]:mr-1.5 [&_li>input]:-ml-5 [&_li>input]:align-middle", "[&_a]:text-primary-text [&_a]:underline [&_a]:underline-offset-2 hover:[&_a]:text-primary-hover", "[&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.9em]", "[&_pre]:whitespace-pre-wrap [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre_code]:bg-transparent [&_pre_code]:p-0", "[&_blockquote]:border-l-2 [&_blockquote]:border-border-strong [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground", "[&_table]:w-full [&_table]:border-collapse [&_th]:border [&_th]:border-border [&_th]:bg-surface [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold", "[&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1 [&_td]:[overflow-wrap:anywhere]", "[&_hr]:border-border [&_img]:inline [&_img]:max-w-full [&_img]:rounded [&_del]:text-muted-foreground");
|
|
8
|
+
const inLink = cn("[&_*]:my-0 [&_h1]:font-semibold [&_h2]:font-semibold [&_h3]:font-semibold [&_ul]:list-inside [&_ol]:list-inside [&_pre]:whitespace-pre-wrap [&_code]:font-mono [&_code]:text-[0.9em]");
|
|
9
|
+
/** Markdown rendered, sanitised before it reaches the page: raw HTML shows as text, links open in a new tab. */
|
|
10
|
+
const MarkdownContent = ({ source, inLink: insideLink = false, className }) => {
|
|
11
|
+
const html = useMemo(() => DOMPurify.sanitize(markdownHtml(source, { inLink: insideLink }), { ADD_ATTR: ["target"] }), [source, insideLink]);
|
|
12
|
+
return /* @__PURE__ */ jsx("div", {
|
|
13
|
+
className: cn(insideLink ? inLink : page, className),
|
|
14
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { MarkdownContent };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Segmented } from "../primitives/segmented.js";
|
|
2
|
+
import { Markdown } from "./markdown.js";
|
|
3
|
+
import { Textarea } from "../primitives/textarea.js";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/markdown/markdown-editor.tsx
|
|
7
|
+
const modes = [{
|
|
8
|
+
value: "write",
|
|
9
|
+
label: "Write"
|
|
10
|
+
}, {
|
|
11
|
+
value: "preview",
|
|
12
|
+
label: "Preview"
|
|
13
|
+
}];
|
|
14
|
+
/**
|
|
15
|
+
* Markdown source in a box that grows with it, as GitHub edits a comment, and a switch to its rendered preview: the
|
|
16
|
+
* text is stored exactly as typed.
|
|
17
|
+
*/
|
|
18
|
+
const MarkdownEditor = ({ value, onChange, label, invalid, placeholder }) => {
|
|
19
|
+
const [mode, setMode] = useState("write");
|
|
20
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
21
|
+
className: "flex flex-col gap-1.5",
|
|
22
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
23
|
+
className: "self-start",
|
|
24
|
+
children: /* @__PURE__ */ jsx(Segmented, {
|
|
25
|
+
value: mode,
|
|
26
|
+
options: modes,
|
|
27
|
+
onChange: setMode,
|
|
28
|
+
label
|
|
29
|
+
})
|
|
30
|
+
}), mode === "write" ? /* @__PURE__ */ jsx(Textarea, {
|
|
31
|
+
rows: 5,
|
|
32
|
+
invalid,
|
|
33
|
+
placeholder,
|
|
34
|
+
value,
|
|
35
|
+
onChange: (event) => onChange(event.target.value)
|
|
36
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
37
|
+
className: "min-h-[7.5rem] rounded-md border border-border px-2.5 py-1.5",
|
|
38
|
+
children: value.trim() === "" ? /* @__PURE__ */ jsx("span", {
|
|
39
|
+
className: "text-faint-foreground",
|
|
40
|
+
children: "Nothing to preview"
|
|
41
|
+
}) : /* @__PURE__ */ jsx(Markdown, { source: value })
|
|
42
|
+
})]
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { MarkdownEditor };
|