@openpolicy/react 0.0.14

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.
@@ -0,0 +1,135 @@
1
+ import * as _openpolicy_core0 from "@openpolicy/core";
2
+ import { BoldNode, CookiePolicyConfig, Document, DocumentSection, HeadingNode, ItalicNode, LinkNode, ListNode, Node, OpenPolicyConfig, ParagraphNode, PrivacyPolicyConfig, TermsOfServiceConfig, TextNode } from "@openpolicy/core";
3
+ import { CSSProperties, ComponentType, ReactNode } from "react";
4
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
5
+
6
+ //#region src/types.d.ts
7
+ type PolicyTheme = Partial<Record<"--op-heading-color" | "--op-body-color" | "--op-section-gap" | "--op-font-family" | "--op-font-size-heading" | "--op-font-weight-heading" | "--op-font-size-body" | "--op-line-height" | "--op-link-color" | "--op-link-color-hover" | "--op-border-color" | "--op-border-radius", string>>;
8
+ interface PolicyComponents {
9
+ Section?: ComponentType<{
10
+ section: DocumentSection;
11
+ children: ReactNode;
12
+ }>;
13
+ Heading?: ComponentType<{
14
+ node: HeadingNode;
15
+ }>;
16
+ Paragraph?: ComponentType<{
17
+ node: ParagraphNode;
18
+ children: ReactNode;
19
+ }>;
20
+ List?: ComponentType<{
21
+ node: ListNode;
22
+ children: ReactNode;
23
+ }>;
24
+ Text?: ComponentType<{
25
+ node: TextNode;
26
+ }>;
27
+ Bold?: ComponentType<{
28
+ node: BoldNode;
29
+ }>;
30
+ Italic?: ComponentType<{
31
+ node: ItalicNode;
32
+ }>;
33
+ Link?: ComponentType<{
34
+ node: LinkNode;
35
+ }>;
36
+ }
37
+ //#endregion
38
+ //#region src/components/CookiePolicy.d.ts
39
+ interface CookiePolicyProps {
40
+ config?: OpenPolicyConfig | CookiePolicyConfig;
41
+ components?: PolicyComponents;
42
+ style?: CSSProperties;
43
+ }
44
+ declare function CookiePolicy({
45
+ config: configProp,
46
+ components,
47
+ style
48
+ }: CookiePolicyProps): react_jsx_runtime0.JSX.Element | null;
49
+ //#endregion
50
+ //#region src/components/defaults.d.ts
51
+ declare function DefaultHeading({
52
+ node
53
+ }: {
54
+ node: HeadingNode;
55
+ }): react_jsx_runtime0.JSX.Element;
56
+ declare function DefaultText({
57
+ node
58
+ }: {
59
+ node: TextNode;
60
+ }): react_jsx_runtime0.JSX.Element;
61
+ declare function DefaultBold({
62
+ node
63
+ }: {
64
+ node: BoldNode;
65
+ }): react_jsx_runtime0.JSX.Element;
66
+ declare function DefaultLink({
67
+ node
68
+ }: {
69
+ node: LinkNode;
70
+ }): react_jsx_runtime0.JSX.Element;
71
+ declare function DefaultSection({
72
+ section,
73
+ children
74
+ }: {
75
+ section: DocumentSection;
76
+ children: ReactNode;
77
+ }): react_jsx_runtime0.JSX.Element;
78
+ declare function DefaultParagraph({
79
+ node: _node,
80
+ children
81
+ }: {
82
+ node: _openpolicy_core0.ParagraphNode;
83
+ children: ReactNode;
84
+ }): react_jsx_runtime0.JSX.Element;
85
+ declare function DefaultList({
86
+ node,
87
+ children
88
+ }: {
89
+ node: _openpolicy_core0.ListNode;
90
+ children: ReactNode;
91
+ }): react_jsx_runtime0.JSX.Element;
92
+ declare function renderNode(node: Node, components: PolicyComponents, key?: number): ReactNode;
93
+ //#endregion
94
+ //#region src/components/PrivacyPolicy.d.ts
95
+ interface PrivacyPolicyProps {
96
+ config?: OpenPolicyConfig | PrivacyPolicyConfig;
97
+ components?: PolicyComponents;
98
+ style?: CSSProperties;
99
+ }
100
+ declare function PrivacyPolicy({
101
+ config: configProp,
102
+ components,
103
+ style
104
+ }: PrivacyPolicyProps): react_jsx_runtime0.JSX.Element | null;
105
+ //#endregion
106
+ //#region src/components/TermsOfService.d.ts
107
+ interface TermsOfServiceProps {
108
+ config?: OpenPolicyConfig | TermsOfServiceConfig;
109
+ components?: PolicyComponents;
110
+ style?: CSSProperties;
111
+ }
112
+ declare function TermsOfService({
113
+ config: configProp,
114
+ components,
115
+ style
116
+ }: TermsOfServiceProps): react_jsx_runtime0.JSX.Element | null;
117
+ //#endregion
118
+ //#region src/context.d.ts
119
+ interface OpenPolicyProviderProps {
120
+ config: OpenPolicyConfig;
121
+ children: ReactNode;
122
+ }
123
+ declare function OpenPolicyProvider({
124
+ config,
125
+ children
126
+ }: OpenPolicyProviderProps): react_jsx_runtime0.JSX.Element;
127
+ //#endregion
128
+ //#region src/render.d.ts
129
+ declare function renderDocument(doc: Document, components?: PolicyComponents): ReactNode;
130
+ //#endregion
131
+ //#region src/styles.d.ts
132
+ declare const defaultStyles = "\n.op-policy {\n --op-font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n --op-font-size-body: 1rem;\n --op-font-size-heading: 1.125rem;\n --op-font-weight-heading: 600;\n --op-line-height: 1.7;\n --op-body-color: #374151;\n --op-heading-color: #111827;\n --op-link-color: #2563eb;\n --op-link-color-hover: #1d4ed8;\n --op-section-gap: 2rem;\n --op-border-color: #e5e7eb;\n --op-border-radius: 0.375rem;\n\n font-family: var(--op-font-family);\n font-size: var(--op-font-size-body);\n color: var(--op-body-color);\n line-height: var(--op-line-height);\n max-width: 65ch;\n}\n\n.op-section {\n margin-bottom: var(--op-section-gap);\n padding-bottom: var(--op-section-gap);\n border-bottom: 1px solid var(--op-border-color);\n}\n.op-section:last-child {\n border-bottom: none;\n margin-bottom: 0;\n padding-bottom: 0;\n}\n\n.op-heading {\n font-size: var(--op-font-size-heading);\n font-weight: var(--op-font-weight-heading);\n color: var(--op-heading-color);\n line-height: 1.3;\n margin: 0 0 0.75rem;\n}\n\n.op-paragraph {\n margin: 0 0 0.75rem;\n}\n.op-paragraph:last-child { margin-bottom: 0; }\n\n.op-list {\n margin: 0 0 0.75rem;\n padding-left: 1.5rem;\n list-style-type: disc;\n}\n.op-list:last-child { margin-bottom: 0; }\n.op-list .op-list {\n margin-top: 0.375rem;\n margin-bottom: 0;\n list-style-type: circle;\n}\n\n.op-list-item {\n margin-bottom: 0.375rem;\n}\n.op-list-item:last-child { margin-bottom: 0; }\n\n.op-bold {\n font-weight: 600;\n color: var(--op-heading-color);\n}\n\n.op-link {\n color: var(--op-link-color);\n text-decoration: underline;\n text-underline-offset: 2px;\n transition: color 0.15s ease;\n}\n.op-link:hover { color: var(--op-link-color-hover); }\n";
133
+ //#endregion
134
+ export { CookiePolicy, DefaultBold, DefaultHeading, DefaultLink, DefaultList, DefaultParagraph, DefaultSection, DefaultText, OpenPolicyProvider as OpenPolicy, type PolicyComponents, type PolicyTheme, PrivacyPolicy, TermsOfService, defaultStyles, renderDocument, renderNode };
135
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/components/CookiePolicy.tsx","../src/components/defaults.tsx","../src/components/PrivacyPolicy.tsx","../src/components/TermsOfService.tsx","../src/context.tsx","../src/render.tsx","../src/styles.ts"],"mappings":";;;;;;KAYY,WAAA,GAAc,OAAA,CACzB,MAAA;AAAA,UAiBgB,gBAAA;EAChB,OAAA,GAAU,aAAA;IAAgB,OAAA,EAAS,eAAA;IAAiB,QAAA,EAAU,SAAA;EAAA;EAC9D,OAAA,GAAU,aAAA;IAAgB,IAAA,EAAM,WAAA;EAAA;EAChC,SAAA,GAAY,aAAA;IAAgB,IAAA,EAAM,aAAA;IAAe,QAAA,EAAU,SAAA;EAAA;EAC3D,IAAA,GAAO,aAAA;IAAgB,IAAA,EAAM,QAAA;IAAU,QAAA,EAAU,SAAA;EAAA;EACjD,IAAA,GAAO,aAAA;IAAgB,IAAA,EAAM,QAAA;EAAA;EAC7B,IAAA,GAAO,aAAA;IAAgB,IAAA,EAAM,QAAA;EAAA;EAC7B,MAAA,GAAS,aAAA;IAAgB,IAAA,EAAM,UAAA;EAAA;EAC/B,IAAA,GAAO,aAAA;IAAgB,IAAA,EAAM,QAAA;EAAA;AAAA;;;UC1BpB,iBAAA;EACT,MAAA,GAAS,gBAAA,GAAmB,kBAAA;EAC5B,UAAA,GAAa,gBAAA;EACb,KAAA,GAAQ,aAAA;AAAA;AAAA,iBAGO,YAAA,CAAA;EACf,MAAA,EAAQ,UAAA;EACR,UAAA;EACA;AAAA,GACE,iBAAA,GAAiB,kBAAA,CAAA,GAAA,CAAA,OAAA;;;iBCVJ,cAAA,CAAA;EAAiB;AAAA;EAAU,IAAA,EAAM,WAAA;AAAA,IAAa,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAU9C,WAAA,CAAA;EAAc;AAAA;EAAU,IAAA,EAAM,QAAA;AAAA,IAAU,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAIxC,WAAA,CAAA;EAAc;AAAA;EAAU,IAAA,EAAM,QAAA;AAAA,IAAU,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQxC,WAAA,CAAA;EAAc;AAAA;EAAU,IAAA,EAAM,QAAA;AAAA,IAAU,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQxC,cAAA,CAAA;EACf,OAAA;EACA;AAAA;EAEA,OAAA,EAAS,eAAA;EACT,QAAA,EAAU,SAAA;AAAA,IACV,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAee,gBAAA,CAAA;EACf,IAAA,EAAM,KAAA;EACN;AAAA;EAEA,IAAA,EAFQ,iBAAA,CAEyB,aAAA;EACjC,QAAA,EAAU,SAAA;AAAA,IACV,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQe,WAAA,CAAA;EACf,IAAA;EACA;AAAA;EAEA,IAAA,EAFQ,iBAAA,CAEyB,QAAA;EACjC,QAAA,EAAU,SAAA;AAAA,IACV,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBASe,UAAA,CACf,IAAA,EAAM,IAAA,EACN,UAAA,EAAY,gBAAA,EACZ,GAAA,YACE,SAAA;;;UCpFO,kBAAA;EACT,MAAA,GAAS,gBAAA,GAAmB,mBAAA;EAC5B,UAAA,GAAa,gBAAA;EACb,KAAA,GAAQ,aAAA;AAAA;AAAA,iBAGO,aAAA,CAAA;EACf,MAAA,EAAQ,UAAA;EACR,UAAA;EACA;AAAA,GACE,kBAAA,GAAkB,kBAAA,CAAA,GAAA,CAAA,OAAA;;;UCVX,mBAAA;EACT,MAAA,GAAS,gBAAA,GAAmB,oBAAA;EAC5B,UAAA,GAAa,gBAAA;EACb,KAAA,GAAQ,aAAA;AAAA;AAAA,iBAGO,cAAA,CAAA;EACf,MAAA,EAAQ,UAAA;EACR,UAAA;EACA;AAAA,GACE,mBAAA,GAAmB,kBAAA,CAAA,GAAA,CAAA,OAAA;;;UCVZ,uBAAA;EACT,MAAA,EAAQ,gBAAA;EACR,QAAA,EAAU,SAAA;AAAA;AAAA,iBAGK,kBAAA,CAAA;EACf,MAAA;EACA;AAAA,GACE,uBAAA,GAAuB,kBAAA,CAAA,GAAA,CAAA,OAAA;;;iBCfV,cAAA,CACf,GAAA,EAAK,QAAA,EACL,UAAA,GAAY,gBAAA,GACV,SAAA;;;cCRU,aAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,256 @@
1
+ import { compile, expandOpenPolicyConfig, isOpenPolicyConfig } from "@openpolicy/core";
2
+ import { createContext, useContext } from "react";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/styles.ts
5
+ const defaultStyles = `
6
+ .op-policy {
7
+ --op-font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
8
+ --op-font-size-body: 1rem;
9
+ --op-font-size-heading: 1.125rem;
10
+ --op-font-weight-heading: 600;
11
+ --op-line-height: 1.7;
12
+ --op-body-color: #374151;
13
+ --op-heading-color: #111827;
14
+ --op-link-color: #2563eb;
15
+ --op-link-color-hover: #1d4ed8;
16
+ --op-section-gap: 2rem;
17
+ --op-border-color: #e5e7eb;
18
+ --op-border-radius: 0.375rem;
19
+
20
+ font-family: var(--op-font-family);
21
+ font-size: var(--op-font-size-body);
22
+ color: var(--op-body-color);
23
+ line-height: var(--op-line-height);
24
+ max-width: 65ch;
25
+ }
26
+
27
+ .op-section {
28
+ margin-bottom: var(--op-section-gap);
29
+ padding-bottom: var(--op-section-gap);
30
+ border-bottom: 1px solid var(--op-border-color);
31
+ }
32
+ .op-section:last-child {
33
+ border-bottom: none;
34
+ margin-bottom: 0;
35
+ padding-bottom: 0;
36
+ }
37
+
38
+ .op-heading {
39
+ font-size: var(--op-font-size-heading);
40
+ font-weight: var(--op-font-weight-heading);
41
+ color: var(--op-heading-color);
42
+ line-height: 1.3;
43
+ margin: 0 0 0.75rem;
44
+ }
45
+
46
+ .op-paragraph {
47
+ margin: 0 0 0.75rem;
48
+ }
49
+ .op-paragraph:last-child { margin-bottom: 0; }
50
+
51
+ .op-list {
52
+ margin: 0 0 0.75rem;
53
+ padding-left: 1.5rem;
54
+ list-style-type: disc;
55
+ }
56
+ .op-list:last-child { margin-bottom: 0; }
57
+ .op-list .op-list {
58
+ margin-top: 0.375rem;
59
+ margin-bottom: 0;
60
+ list-style-type: circle;
61
+ }
62
+
63
+ .op-list-item {
64
+ margin-bottom: 0.375rem;
65
+ }
66
+ .op-list-item:last-child { margin-bottom: 0; }
67
+
68
+ .op-bold {
69
+ font-weight: 600;
70
+ color: var(--op-heading-color);
71
+ }
72
+
73
+ .op-link {
74
+ color: var(--op-link-color);
75
+ text-decoration: underline;
76
+ text-underline-offset: 2px;
77
+ transition: color 0.15s ease;
78
+ }
79
+ .op-link:hover { color: var(--op-link-color-hover); }
80
+ `;
81
+ //#endregion
82
+ //#region src/context.tsx
83
+ const OpenPolicyContext = createContext({ config: null });
84
+ function OpenPolicyProvider({ config, children }) {
85
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("style", {
86
+ href: "@openpolicy/react",
87
+ precedence: "default",
88
+ children: defaultStyles
89
+ }), /* @__PURE__ */ jsx(OpenPolicyContext.Provider, {
90
+ value: { config },
91
+ children
92
+ })] });
93
+ }
94
+ //#endregion
95
+ //#region src/components/defaults.tsx
96
+ function DefaultHeading({ node }) {
97
+ return /* @__PURE__ */ jsx(`h${node.level ?? 2}`, {
98
+ "data-op-heading": true,
99
+ className: "op-heading",
100
+ children: node.value
101
+ });
102
+ }
103
+ function DefaultText({ node }) {
104
+ return /* @__PURE__ */ jsx(Fragment, { children: node.value });
105
+ }
106
+ function DefaultBold({ node }) {
107
+ return /* @__PURE__ */ jsx("strong", {
108
+ className: "op-bold",
109
+ children: node.value
110
+ });
111
+ }
112
+ function DefaultItalic({ node }) {
113
+ return /* @__PURE__ */ jsx("em", {
114
+ className: "op-italic",
115
+ children: node.value
116
+ });
117
+ }
118
+ function DefaultLink({ node }) {
119
+ return /* @__PURE__ */ jsx("a", {
120
+ href: node.href,
121
+ className: "op-link",
122
+ children: node.value
123
+ });
124
+ }
125
+ function DefaultSection({ section, children }) {
126
+ return /* @__PURE__ */ jsx("section", {
127
+ "data-op-section": true,
128
+ className: "op-section",
129
+ id: section.id,
130
+ ...section.context?.reason && { "data-op-reason": section.context.reason },
131
+ children
132
+ });
133
+ }
134
+ function DefaultParagraph({ node: _node, children }) {
135
+ return /* @__PURE__ */ jsx("p", {
136
+ "data-op-paragraph": true,
137
+ className: "op-paragraph",
138
+ children
139
+ });
140
+ }
141
+ function DefaultList({ node, children }) {
142
+ return /* @__PURE__ */ jsx(node.ordered ? "ol" : "ul", {
143
+ "data-op-list": true,
144
+ className: "op-list",
145
+ children
146
+ });
147
+ }
148
+ function renderNode(node, components, key) {
149
+ switch (node.type) {
150
+ case "document": return /* @__PURE__ */ jsx(Fragment, { children: node.sections.map((s, i) => renderNode(s, components, i)) });
151
+ case "section": return /* @__PURE__ */ jsx(components.Section ?? DefaultSection, {
152
+ section: node,
153
+ children: node.content.map((n, i) => renderNode(n, components, i))
154
+ }, key);
155
+ case "heading": return /* @__PURE__ */ jsx(components.Heading ?? DefaultHeading, { node }, key);
156
+ case "paragraph": {
157
+ const children = node.children.map((n, i) => renderNode(n, components, i));
158
+ if (components.Paragraph) return /* @__PURE__ */ jsx(components.Paragraph, {
159
+ node,
160
+ children
161
+ }, key);
162
+ return /* @__PURE__ */ jsx("p", {
163
+ "data-op-paragraph": true,
164
+ className: "op-paragraph",
165
+ children
166
+ }, key);
167
+ }
168
+ case "list": {
169
+ const children = node.items.map((item, i) => renderNode(item, components, i));
170
+ if (components.List) return /* @__PURE__ */ jsx(components.List, {
171
+ node,
172
+ children
173
+ }, key);
174
+ return /* @__PURE__ */ jsx(node.ordered ? "ol" : "ul", {
175
+ "data-op-list": true,
176
+ className: "op-list",
177
+ children
178
+ }, key);
179
+ }
180
+ case "listItem": return /* @__PURE__ */ jsx("li", {
181
+ "data-op-list-item": true,
182
+ className: "op-list-item",
183
+ children: node.children.map((n, i) => renderNode(n, components, i))
184
+ }, key);
185
+ case "text": return /* @__PURE__ */ jsx(components.Text ?? DefaultText, { node }, key);
186
+ case "bold": return /* @__PURE__ */ jsx(components.Bold ?? DefaultBold, { node }, key);
187
+ case "italic": return /* @__PURE__ */ jsx(components.Italic ?? DefaultItalic, { node }, key);
188
+ case "link": return /* @__PURE__ */ jsx(components.Link ?? DefaultLink, { node }, key);
189
+ }
190
+ }
191
+ //#endregion
192
+ //#region src/render.tsx
193
+ function renderDocument(doc, components = {}) {
194
+ return renderNode(doc, components);
195
+ }
196
+ //#endregion
197
+ //#region src/components/CookiePolicy.tsx
198
+ function CookiePolicy({ config: configProp, components, style }) {
199
+ const { config: contextConfig } = useContext(OpenPolicyContext);
200
+ const config = configProp ?? contextConfig ?? void 0;
201
+ if (!config) return null;
202
+ const input = isOpenPolicyConfig(config) ? expandOpenPolicyConfig(config).find((i) => i.type === "cookie") : {
203
+ type: "cookie",
204
+ ...config
205
+ };
206
+ if (!input) return null;
207
+ const doc = compile(input);
208
+ return /* @__PURE__ */ jsx("div", {
209
+ "data-op-policy": true,
210
+ className: "op-policy",
211
+ style,
212
+ children: renderDocument(doc, components)
213
+ });
214
+ }
215
+ //#endregion
216
+ //#region src/components/PrivacyPolicy.tsx
217
+ function PrivacyPolicy({ config: configProp, components, style }) {
218
+ const { config: contextConfig } = useContext(OpenPolicyContext);
219
+ const config = configProp ?? contextConfig ?? void 0;
220
+ if (!config) return null;
221
+ const input = isOpenPolicyConfig(config) ? expandOpenPolicyConfig(config).find((i) => i.type === "privacy") : {
222
+ type: "privacy",
223
+ ...config
224
+ };
225
+ if (!input) return null;
226
+ const doc = compile(input);
227
+ return /* @__PURE__ */ jsx("div", {
228
+ "data-op-policy": true,
229
+ className: "op-policy",
230
+ style,
231
+ children: renderDocument(doc, components)
232
+ });
233
+ }
234
+ //#endregion
235
+ //#region src/components/TermsOfService.tsx
236
+ function TermsOfService({ config: configProp, components, style }) {
237
+ const { config: contextConfig } = useContext(OpenPolicyContext);
238
+ const config = configProp ?? contextConfig ?? void 0;
239
+ if (!config) return null;
240
+ const input = isOpenPolicyConfig(config) ? expandOpenPolicyConfig(config).find((i) => i.type === "terms") : {
241
+ type: "terms",
242
+ ...config
243
+ };
244
+ if (!input) return null;
245
+ const doc = compile(input);
246
+ return /* @__PURE__ */ jsx("div", {
247
+ "data-op-policy": true,
248
+ className: "op-policy",
249
+ style,
250
+ children: renderDocument(doc, components)
251
+ });
252
+ }
253
+ //#endregion
254
+ export { CookiePolicy, DefaultBold, DefaultHeading, DefaultLink, DefaultList, DefaultParagraph, DefaultSection, DefaultText, OpenPolicyProvider as OpenPolicy, PrivacyPolicy, TermsOfService, defaultStyles, renderDocument, renderNode };
255
+
256
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/styles.ts","../src/context.tsx","../src/components/defaults.tsx","../src/render.tsx","../src/components/CookiePolicy.tsx","../src/components/PrivacyPolicy.tsx","../src/components/TermsOfService.tsx"],"sourcesContent":["export const defaultStyles = `\n.op-policy {\n --op-font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n --op-font-size-body: 1rem;\n --op-font-size-heading: 1.125rem;\n --op-font-weight-heading: 600;\n --op-line-height: 1.7;\n --op-body-color: #374151;\n --op-heading-color: #111827;\n --op-link-color: #2563eb;\n --op-link-color-hover: #1d4ed8;\n --op-section-gap: 2rem;\n --op-border-color: #e5e7eb;\n --op-border-radius: 0.375rem;\n\n font-family: var(--op-font-family);\n font-size: var(--op-font-size-body);\n color: var(--op-body-color);\n line-height: var(--op-line-height);\n max-width: 65ch;\n}\n\n.op-section {\n margin-bottom: var(--op-section-gap);\n padding-bottom: var(--op-section-gap);\n border-bottom: 1px solid var(--op-border-color);\n}\n.op-section:last-child {\n border-bottom: none;\n margin-bottom: 0;\n padding-bottom: 0;\n}\n\n.op-heading {\n font-size: var(--op-font-size-heading);\n font-weight: var(--op-font-weight-heading);\n color: var(--op-heading-color);\n line-height: 1.3;\n margin: 0 0 0.75rem;\n}\n\n.op-paragraph {\n margin: 0 0 0.75rem;\n}\n.op-paragraph:last-child { margin-bottom: 0; }\n\n.op-list {\n margin: 0 0 0.75rem;\n padding-left: 1.5rem;\n list-style-type: disc;\n}\n.op-list:last-child { margin-bottom: 0; }\n.op-list .op-list {\n margin-top: 0.375rem;\n margin-bottom: 0;\n list-style-type: circle;\n}\n\n.op-list-item {\n margin-bottom: 0.375rem;\n}\n.op-list-item:last-child { margin-bottom: 0; }\n\n.op-bold {\n font-weight: 600;\n color: var(--op-heading-color);\n}\n\n.op-link {\n color: var(--op-link-color);\n text-decoration: underline;\n text-underline-offset: 2px;\n transition: color 0.15s ease;\n}\n.op-link:hover { color: var(--op-link-color-hover); }\n`;\n","import type { OpenPolicyConfig } from \"@openpolicy/core\";\nimport { createContext, type ReactNode } from \"react\";\nimport { defaultStyles } from \"./styles\";\n\ninterface OpenPolicyContextValue {\n\tconfig: OpenPolicyConfig | null;\n}\n\nexport const OpenPolicyContext = createContext<OpenPolicyContextValue>({\n\tconfig: null,\n});\n\ninterface OpenPolicyProviderProps {\n\tconfig: OpenPolicyConfig;\n\tchildren: ReactNode;\n}\n\nexport function OpenPolicyProvider({\n\tconfig,\n\tchildren,\n}: OpenPolicyProviderProps) {\n\treturn (\n\t\t<>\n\t\t\t<style href=\"@openpolicy/react\" precedence=\"default\">\n\t\t\t\t{defaultStyles}\n\t\t\t</style>\n\t\t\t<OpenPolicyContext.Provider value={{ config }}>\n\t\t\t\t{children}\n\t\t\t</OpenPolicyContext.Provider>\n\t\t</>\n\t);\n}\n","import type {\n\tBoldNode,\n\tDocumentSection,\n\tHeadingNode,\n\tItalicNode,\n\tLinkNode,\n\tNode,\n\tTextNode,\n} from \"@openpolicy/core\";\nimport type { ReactNode } from \"react\";\nimport type { PolicyComponents } from \"../types\";\n\nexport function DefaultHeading({ node }: { node: HeadingNode }) {\n\tconst level = node.level ?? 2;\n\tconst Tag = `h${level}` as \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\";\n\treturn (\n\t\t<Tag data-op-heading className=\"op-heading\">\n\t\t\t{node.value}\n\t\t</Tag>\n\t);\n}\n\nexport function DefaultText({ node }: { node: TextNode }) {\n\treturn <>{node.value}</>;\n}\n\nexport function DefaultBold({ node }: { node: BoldNode }) {\n\treturn <strong className=\"op-bold\">{node.value}</strong>;\n}\n\nfunction DefaultItalic({ node }: { node: ItalicNode }) {\n\treturn <em className=\"op-italic\">{node.value}</em>;\n}\n\nexport function DefaultLink({ node }: { node: LinkNode }) {\n\treturn (\n\t\t<a href={node.href} className=\"op-link\">\n\t\t\t{node.value}\n\t\t</a>\n\t);\n}\n\nexport function DefaultSection({\n\tsection,\n\tchildren,\n}: {\n\tsection: DocumentSection;\n\tchildren: ReactNode;\n}) {\n\treturn (\n\t\t<section\n\t\t\tdata-op-section\n\t\t\tclassName=\"op-section\"\n\t\t\tid={section.id}\n\t\t\t{...(section.context?.reason && {\n\t\t\t\t\"data-op-reason\": section.context.reason,\n\t\t\t})}\n\t\t>\n\t\t\t{children}\n\t\t</section>\n\t);\n}\n\nexport function DefaultParagraph({\n\tnode: _node,\n\tchildren,\n}: {\n\tnode: import(\"@openpolicy/core\").ParagraphNode;\n\tchildren: ReactNode;\n}) {\n\treturn (\n\t\t<p data-op-paragraph className=\"op-paragraph\">\n\t\t\t{children}\n\t\t</p>\n\t);\n}\n\nexport function DefaultList({\n\tnode,\n\tchildren,\n}: {\n\tnode: import(\"@openpolicy/core\").ListNode;\n\tchildren: ReactNode;\n}) {\n\tconst Tag = node.ordered ? \"ol\" : \"ul\";\n\treturn (\n\t\t<Tag data-op-list className=\"op-list\">\n\t\t\t{children}\n\t\t</Tag>\n\t);\n}\n\nexport function renderNode(\n\tnode: Node,\n\tcomponents: PolicyComponents,\n\tkey?: number,\n): ReactNode {\n\tswitch (node.type) {\n\t\tcase \"document\":\n\t\t\treturn <>{node.sections.map((s, i) => renderNode(s, components, i))}</>;\n\n\t\tcase \"section\": {\n\t\t\tconst SectionComp = components.Section ?? DefaultSection;\n\t\t\treturn (\n\t\t\t\t<SectionComp key={key} section={node}>\n\t\t\t\t\t{node.content.map((n, i) => renderNode(n, components, i))}\n\t\t\t\t</SectionComp>\n\t\t\t);\n\t\t}\n\n\t\tcase \"heading\": {\n\t\t\tconst HeadingComp = components.Heading ?? DefaultHeading;\n\t\t\treturn <HeadingComp key={key} node={node} />;\n\t\t}\n\n\t\tcase \"paragraph\": {\n\t\t\tconst children = node.children.map((n, i) =>\n\t\t\t\trenderNode(n, components, i),\n\t\t\t);\n\t\t\tif (components.Paragraph)\n\t\t\t\treturn (\n\t\t\t\t\t<components.Paragraph key={key} node={node}>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</components.Paragraph>\n\t\t\t\t);\n\t\t\treturn (\n\t\t\t\t<p key={key} data-op-paragraph className=\"op-paragraph\">\n\t\t\t\t\t{children}\n\t\t\t\t</p>\n\t\t\t);\n\t\t}\n\n\t\tcase \"list\": {\n\t\t\tconst children = node.items.map((item, i) =>\n\t\t\t\trenderNode(item, components, i),\n\t\t\t);\n\t\t\tif (components.List)\n\t\t\t\treturn (\n\t\t\t\t\t<components.List key={key} node={node}>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</components.List>\n\t\t\t\t);\n\t\t\tconst ListTag = node.ordered ? \"ol\" : \"ul\";\n\t\t\treturn (\n\t\t\t\t<ListTag key={key} data-op-list className=\"op-list\">\n\t\t\t\t\t{children}\n\t\t\t\t</ListTag>\n\t\t\t);\n\t\t}\n\n\t\tcase \"listItem\":\n\t\t\treturn (\n\t\t\t\t<li key={key} data-op-list-item className=\"op-list-item\">\n\t\t\t\t\t{node.children.map((n, i) => renderNode(n, components, i))}\n\t\t\t\t</li>\n\t\t\t);\n\n\t\tcase \"text\": {\n\t\t\tconst Comp = components.Text ?? DefaultText;\n\t\t\treturn <Comp key={key} node={node} />;\n\t\t}\n\t\tcase \"bold\": {\n\t\t\tconst Comp = components.Bold ?? DefaultBold;\n\t\t\treturn <Comp key={key} node={node} />;\n\t\t}\n\t\tcase \"italic\": {\n\t\t\tconst Comp = components.Italic ?? DefaultItalic;\n\t\t\treturn <Comp key={key} node={node} />;\n\t\t}\n\t\tcase \"link\": {\n\t\t\tconst Comp = components.Link ?? DefaultLink;\n\t\t\treturn <Comp key={key} node={node} />;\n\t\t}\n\t}\n}\n","import type { Document } from \"@openpolicy/core\";\nimport type { ReactNode } from \"react\";\nimport { renderNode } from \"./components/defaults\";\nimport type { PolicyComponents } from \"./types\";\n\nexport function renderDocument(\n\tdoc: Document,\n\tcomponents: PolicyComponents = {},\n): ReactNode {\n\treturn renderNode(doc, components);\n}\n","import {\n\ttype CookiePolicyConfig,\n\tcompile,\n\texpandOpenPolicyConfig,\n\tisOpenPolicyConfig,\n\ttype OpenPolicyConfig,\n} from \"@openpolicy/core\";\nimport { type CSSProperties, useContext } from \"react\";\nimport { OpenPolicyContext } from \"../context\";\nimport { renderDocument } from \"../render\";\nimport type { PolicyComponents } from \"../types\";\n\ninterface CookiePolicyProps {\n\tconfig?: OpenPolicyConfig | CookiePolicyConfig;\n\tcomponents?: PolicyComponents;\n\tstyle?: CSSProperties;\n}\n\nexport function CookiePolicy({\n\tconfig: configProp,\n\tcomponents,\n\tstyle,\n}: CookiePolicyProps) {\n\tconst { config: contextConfig } = useContext(OpenPolicyContext);\n\tconst config = configProp ?? contextConfig ?? undefined;\n\tif (!config) return null;\n\tconst input = isOpenPolicyConfig(config)\n\t\t? expandOpenPolicyConfig(config).find((i) => i.type === \"cookie\")\n\t\t: { type: \"cookie\" as const, ...config };\n\tif (!input) return null;\n\tconst doc = compile(input);\n\treturn (\n\t\t<div data-op-policy className=\"op-policy\" style={style}>\n\t\t\t{renderDocument(doc, components)}\n\t\t</div>\n\t);\n}\n","import {\n\tcompile,\n\texpandOpenPolicyConfig,\n\tisOpenPolicyConfig,\n\ttype OpenPolicyConfig,\n\ttype PrivacyPolicyConfig,\n} from \"@openpolicy/core\";\nimport { type CSSProperties, useContext } from \"react\";\nimport { OpenPolicyContext } from \"../context\";\nimport { renderDocument } from \"../render\";\nimport type { PolicyComponents } from \"../types\";\n\ninterface PrivacyPolicyProps {\n\tconfig?: OpenPolicyConfig | PrivacyPolicyConfig;\n\tcomponents?: PolicyComponents;\n\tstyle?: CSSProperties;\n}\n\nexport function PrivacyPolicy({\n\tconfig: configProp,\n\tcomponents,\n\tstyle,\n}: PrivacyPolicyProps) {\n\tconst { config: contextConfig } = useContext(OpenPolicyContext);\n\tconst config = configProp ?? contextConfig ?? undefined;\n\tif (!config) return null;\n\tconst input = isOpenPolicyConfig(config)\n\t\t? expandOpenPolicyConfig(config).find((i) => i.type === \"privacy\")\n\t\t: { type: \"privacy\" as const, ...config };\n\tif (!input) return null;\n\tconst doc = compile(input);\n\treturn (\n\t\t<div data-op-policy className=\"op-policy\" style={style}>\n\t\t\t{renderDocument(doc, components)}\n\t\t</div>\n\t);\n}\n","import {\n\tcompile,\n\texpandOpenPolicyConfig,\n\tisOpenPolicyConfig,\n\ttype OpenPolicyConfig,\n\ttype TermsOfServiceConfig,\n} from \"@openpolicy/core\";\nimport { type CSSProperties, useContext } from \"react\";\nimport { OpenPolicyContext } from \"../context\";\nimport { renderDocument } from \"../render\";\nimport type { PolicyComponents } from \"../types\";\n\ninterface TermsOfServiceProps {\n\tconfig?: OpenPolicyConfig | TermsOfServiceConfig;\n\tcomponents?: PolicyComponents;\n\tstyle?: CSSProperties;\n}\n\nexport function TermsOfService({\n\tconfig: configProp,\n\tcomponents,\n\tstyle,\n}: TermsOfServiceProps) {\n\tconst { config: contextConfig } = useContext(OpenPolicyContext);\n\tconst config = configProp ?? contextConfig ?? undefined;\n\tif (!config) return null;\n\tconst input = isOpenPolicyConfig(config)\n\t\t? expandOpenPolicyConfig(config).find((i) => i.type === \"terms\")\n\t\t: { type: \"terms\" as const, ...config };\n\tif (!input) return null;\n\tconst doc = compile(input);\n\treturn (\n\t\t<div data-op-policy className=\"op-policy\" style={style}>\n\t\t\t{renderDocument(doc, components)}\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@openpolicy/react",
3
+ "version": "0.0.14",
4
+ "type": "module",
5
+ "description": "React components and hooks for OpenPolicy",
6
+ "license": "GPL-3.0-only",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/jamiedavenport/openpolicy",
10
+ "directory": "packages/react"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "styles.css",
15
+ "README.md"
16
+ ],
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/index.js",
20
+ "types": "./dist/index.d.ts"
21
+ },
22
+ "./styles.css": "./styles.css"
23
+ },
24
+ "scripts": {
25
+ "dev": "rolldown -c --watch",
26
+ "build": "rolldown -c",
27
+ "check-types": "tsc --noEmit",
28
+ "test": "bun test"
29
+ },
30
+ "peerDependencies": {
31
+ "react": ">=19",
32
+ "react-dom": ">=19"
33
+ },
34
+ "dependencies": {
35
+ "@openpolicy/core": "workspace:*"
36
+ },
37
+ "devDependencies": {
38
+ "@openpolicy/tooling": "workspace:*",
39
+ "@types/react": "^19.0.0",
40
+ "react": "^19.0.0"
41
+ },
42
+ "publishConfig": {
43
+ "exports": {
44
+ ".": {
45
+ "import": "./dist/index.js",
46
+ "types": "./dist/index.d.ts"
47
+ },
48
+ "./styles.css": "./styles.css"
49
+ }
50
+ }
51
+ }
package/styles.css ADDED
@@ -0,0 +1,30 @@
1
+ /* @openpolicy/react/styles.css — opt-in default styles */
2
+ :root {
3
+ --op-font-family: system-ui, sans-serif;
4
+ --op-font-size-body: 1rem;
5
+ --op-font-size-heading: 1.25rem;
6
+ --op-heading-color: #111;
7
+ --op-body-color: #444;
8
+ --op-section-gap: 2rem;
9
+ --op-border-color: #e5e5e5;
10
+ --op-border-radius: 0.25rem;
11
+ --op-line-height: 1.6;
12
+ }
13
+
14
+ [data-op-policy] {
15
+ font-family: var(--op-font-family);
16
+ color: var(--op-body-color);
17
+ }
18
+
19
+ [data-op-section] {
20
+ margin-bottom: var(--op-section-gap);
21
+ }
22
+
23
+ [data-op-heading] {
24
+ color: var(--op-heading-color);
25
+ font-size: var(--op-font-size-heading);
26
+ }
27
+
28
+ [data-op-body] {
29
+ line-height: var(--op-line-height);
30
+ }