@redacto.io/consent-sdk-react 10.2.2-beta.3 → 10.3.0-beta.4

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 CHANGED
@@ -87,7 +87,7 @@ The SDK follows a client-server architecture pattern:
87
87
  - Token-based authentication
88
88
 
89
89
  - **Configuration**
90
- - Customizable UI settings
90
+ - Appearance set in the Redacto console (templates, colours, styles)
91
91
  - Language preferences
92
92
  - API endpoint configuration
93
93
 
@@ -326,7 +326,7 @@ A modal popup component for consent collection. Displays a full-screen modal wit
326
326
  | `ledgerBaseUrl` | `string` | No | - | Go ledger base URL. When set, consent writes and prior-consent checks route through the ledger (falls back: ledger → baseUrl → default). Omit to keep the legacy consent-server path. |
327
327
  | `blockUI` | `boolean` | No | `true` | Whether to block UI interaction |
328
328
  | `language` | `string` | No | `"en"` | Language code |
329
- | `settings` | `object` | No | - | Custom styling options |
329
+ | `settings` | `object` | No | - | Optional code overrides; win over the console appearance key by key. See [Appearance](#notice-appearance) |
330
330
  | `applicationId` | `string` | No | - | Application-specific UUID |
331
331
  | `validateAgainst` | `"all" \| "required"` | No | `"all"` | Consent validation mode (see below) |
332
332
  | `includeFullyConsentedData` | `boolean` | No | `false` | When true, API returns 200 with pre-selected purposes instead of 409 when user has already consented |
@@ -412,7 +412,7 @@ The component automatically submits consent when all of the following conditions
412
412
  | `baseUrl` | `string` | No | - | Base URL for the consent API |
413
413
  | `ledgerBaseUrl` | `string` | No | - | Go ledger base URL. When set, consent writes and already-consented checks route through the ledger. Omit for legacy behavior. |
414
414
  | `language` | `string` | No | `"en"` | Language code |
415
- | `settings` | `object` | No | - | Custom styling options |
415
+ | `settings` | `object` | No | - | Optional code overrides of the console appearance |
416
416
  | `applicationId` | `string` | No | - | Application-specific UUID |
417
417
  | `onAccept` | `() => void` | No | - | Callback when consent is accepted |
418
418
  | `onDecline` | `() => void` | No | - | Callback when consent is declined |
@@ -745,56 +745,136 @@ export function AssistedConsent() {
745
745
  }
746
746
  ```
747
747
 
748
- ### Custom Styling
748
+ <a id="notice-appearance"></a>
749
749
 
750
- `RedactoNoticeConsent` and `RedactoNoticeConsentInline` support extensive styling customization via the `settings` prop, which overrides the notice's own API configuration. (`RedactoNoticeAssisted` does not take a `settings` prop — it themes itself entirely from the notice's API configuration, such as primary/secondary colour and font.)
750
+ ### Appearance (set in the Redacto console)
751
+
752
+ How a notice looks is configured by your workspace admin in the Redacto console,
753
+ in the notice wizard's **Display settings → Appearance** step, and served with the
754
+ notice. No code change is needed: every notice component (`RedactoNoticeConsent`,
755
+ `RedactoNoticeConsentInline`, `RedactoNoticeAssisted`) on every platform renders
756
+ what the console saved.
757
+
758
+ The console offers:
759
+
760
+ - **Templates:** Classic, Glass and Dark, as starting points.
761
+ - **Style:**
762
+ - **`classic`:** the centred modal.
763
+ - **`minimal`:** flat, with hairline edges and no shadows.
764
+ - **`soft`:** a lifted, rounded card with brand-washed purpose rows and pill buttons.
765
+ - **`glass`:** a translucent, frosted sheet. It docks to the bottom on phones and floats as a card on wider screens. The notice text and the grievance/DPO block collapse into sections. On phones, Accept Selected and Decline sit side by side under Accept All.
766
+ - **Colours:** Light, Dark, From brand colour, or fully Custom. There are per-element colours for the background, text, links, borders, overlay and each button, the toggle states, and the **text-to-speech highlight**.
767
+ - **Layout, in any style:**
768
+ - on phones, a centred **modal** or a **bottom sheet**
769
+ - on wider screens, **centre**, **bottom right**, **bottom left** or a full-width **bottom bar**
770
+ - whether the page behind is **dimmed**
771
+ - **collapsible** notice text and grievance/DPO sections
772
+ - a **stacked or paired** phone footer
773
+ - **Colours:** optionally a second, dark palette that applies automatically when the visitor's device is in **dark mode**.
774
+ - **Size and type:** the card's **max width**, the **logo size** and a **text size** (small, regular or large).
775
+ - **Corner radius**, the **selection control** (checkbox, radio or dropdown), whether checkbox rows are drawn as **checkboxes or switches** (in any style), an optional **"are you sure" step** before submitting, and whether the notice **animates**.
776
+ - **Custom CSS**, scoped to the notice (see below).
777
+
778
+ A notice whose admin set no appearance renders as classic from its brand colours,
779
+ exactly as before. Developers can still override any of it in code (below), and
780
+ code wins. Motion respects `prefers-reduced-motion`.
781
+
782
+ #### Custom CSS
783
+
784
+ Admins can add CSS for a notice in the console, and hosts can pass `settings.customCss`. It applies only to that notice: the SDK wraps it in `@scope ([data-redacto-notice-id="<notice uuid>"])` and removes it when the notice unmounts. CSS carrying `@import`, `javascript:`, `expression(`, `behavior:` or `</style` (even escaped) is refused whole, as is anything over 20,000 characters and anything whose brackets don't pair up (a stray `}` would close the scope).
785
+
786
+ Target the notice's parts through stable hooks:
787
+
788
+ `root`, `overlay`, `header`, `logo`, `title`, `language`, `notice-text`, `purposes`, `product`, `purpose`, `purpose-title`, `data-element`, `section`, `dpo`, `footer`, `accept-all`, `accept-selected`, `decline`, `confirm-dialog`, `otp`
789
+
790
+ The notice styles its parts inline, so use `!important`:
791
+
792
+ ```css
793
+ [data-redacto-part="accept-all"] {
794
+ border-radius: 0 !important;
795
+ text-transform: uppercase;
796
+ }
797
+ ```
798
+
799
+ `@scope` is supported by current Chrome, Edge, Safari (17.4+) and Firefox (128+); older browsers skip the custom CSS and draw the notice as configured.
800
+
801
+ #### Overriding the console in code (`settings`)
802
+
803
+ `settings` is optional. Anything you set there **wins over the console, key by key**. Every key you leave out keeps the console's value, which in turn falls back to the notice's brand colours.
804
+
805
+ The order is:
806
+
807
+ 1. host `settings`
808
+ 2. console appearance
809
+ 3. brand colours and SDK defaults
810
+
811
+ `settings` covers everything the console does:
751
812
 
752
813
  ```tsx
753
- const customSettings = {
754
- button: {
755
- accept: {
756
- backgroundColor: "#9810fa",
757
- textColor: "white",
758
- },
759
- decline: {
760
- backgroundColor: "#0a0a14",
761
- textColor: "white",
762
- },
763
- language: {
764
- backgroundColor: "#0a0a14",
765
- textColor: "white",
766
- selectedBackgroundColor: "#9810fa",
767
- selectedTextColor: "white",
768
- },
769
- },
770
- borderRadius: "8px",
771
- backgroundColor: "#1a1a2e",
772
- headingColor: "#ffffff",
773
- textColor: "#e6e6e6",
774
- borderColor: "white",
775
- link: "#9810fa",
776
- font: "Arial, sans-serif", // Optional: overrides the notice's Font Family
777
- };
778
-
779
- // Use in component
780
814
  <RedactoNoticeConsent
781
815
  // ... other props
782
- settings={customSettings}
783
- />;
816
+ settings={{
817
+ theme: "glass", // "classic" | "glass" | "minimal" | "soft"
818
+ backgroundColor: "#ffffff",
819
+ surfaceColor: "#f8fafc",
820
+ headingColor: "#101828",
821
+ textColor: "#344054",
822
+ mutedTextColor: "#475467",
823
+ borderColor: "#d0d5dd",
824
+ overlayColor: "rgba(0, 0, 0, 0.5)",
825
+ link: "#4f87ff",
826
+ borderRadius: "12px",
827
+ font: "Inter, system-ui, sans-serif",
828
+ button: {
829
+ accept: { backgroundColor: "#4f87ff", textColor: "#ffffff" }, // brand accent; Accept All's fallback
830
+ acceptAll: { backgroundColor: "#4f87ff", textColor: "#ffffff" },
831
+ acceptSelected: { backgroundColor: "#ffffff", textColor: "#4f87ff" },
832
+ decline: { backgroundColor: "#ffffff", textColor: "#000000", borderColor: "#d0d5dd" },
833
+ language: {
834
+ backgroundColor: "#ffffff",
835
+ textColor: "#344054",
836
+ selectedBackgroundColor: "#f3f4f6",
837
+ selectedTextColor: "#344054",
838
+ },
839
+ },
840
+ toggle: { onColor: "#4f87ff", offColor: "#d0d5dd", knobColor: "#ffffff" },
841
+ ttsHighlight: { backgroundColor: "#FFF9C4", textColor: "#111827" },
842
+ selectionControl: "checkbox", // "checkbox" | "radio" | "dropdown"
843
+ controlStyle: "switch", // "checkbox" | "switch", in any style (default: checkboxes)
844
+ confirmBeforeSubmit: false,
845
+ mobileLayout: "sheet", // "modal" | "sheet"
846
+ desktopPosition: "bottom-right", // "center" | "bottom-right" | "bottom-left" | "bottom-bar"
847
+ backdrop: "none", // "dim" | "none"
848
+ collapsibleSections: true,
849
+ phoneFooter: "paired", // "stacked" | "paired"
850
+ autoDark: true, // follow the device's dark mode with darkPalette (else the console's)
851
+ darkPalette: { backgroundColor: "#0b1220", headingColor: "#f8fafc", textColor: "#cbd5e1" },
852
+ maxWidth: "560px",
853
+ logoSize: "40px",
854
+ textScale: "lg", // "sm" | "md" | "lg"
855
+ motion: false,
856
+ customCss: '[data-redacto-part="accept-all"] { border-radius: 0 !important; }',
857
+ }}
858
+ />
784
859
  ```
785
860
 
786
- ### Available Style Properties
861
+ Existing integrations keep working unchanged. `button.accept` keeps its meaning: it is the brand accent, and Accept All's colour when `acceptAll` is unset. Host colours override the light palette; when automatic dark mode is on and the device is dark, the dark palette replaces them, and `darkPalette` is where a host overrides it. `RedactoNoticeConsentInline` and `RedactoNoticeAssisted` take the same `settings` and use the parts they draw:
862
+ - **Inline:** text and control colours, the selection control and switches, text size, dark mode and custom CSS.
863
+ - **Assisted:** the full palette, style shape, corners, text size, logo position, dark mode and custom CSS.
864
+
865
+ Layout, size and motion keys apply to the modal notice only. `docs/sdk-appearance-spec.md` lists every console setting and which component draws it.
866
+
867
+ #### Previewing a notice (console use)
868
+
869
+ `RedactoNoticePreview` draws a notice from given content, the same way a visitor
870
+ sees it. It fetches, submits, plays and focuses nothing. It exists for the Redacto
871
+ console's live preview and is not meant for visitor-facing pages.
787
872
 
788
- - `backgroundColor`: Background color of the modal/form
789
- - `headingColor`: Color for headings
790
- - `textColor`: Color for body text
791
- - `borderColor`: Color for borders
792
- - `borderRadius`: Border radius for rounded corners
793
- - `link`: Color for links
794
- - `font`: Font family (optional) — overrides the Font Family configured on the notice
795
- - `button.accept`: Styles for accept button
796
- - `button.decline`: Styles for decline button
797
- - `button.language`: Styles for language selector
873
+ ```tsx
874
+ import { RedactoNoticePreview } from "@redacto.io/consent-sdk-react";
875
+
876
+ <RedactoNoticePreview content={noticeReadResponse} isMobile />;
877
+ ```
798
878
 
799
879
  #### Font family
800
880
 
@@ -803,14 +883,9 @@ Redacto console (`active_config.font_preference`), so the rendered notice matche
803
883
  console's live preview without any host configuration.
804
884
 
805
885
  Resolution order is `settings.font` → the notice's Font Family → the host page's font.
806
- Pass `settings.font` only when the host needs to override the configured family; omit it
807
- and the console selection is used. The selected family is expanded into a full CSS stack
808
- with a generic fallback (`Times New Roman` becomes `"Times New Roman", Times, serif`).
809
-
810
- The two sources are deliberately **not** interchangeable. The notice's own Font Family must be one
811
- of the families above; a stored value that is no longer offered renders as Arial, so the console and
812
- the notice can never disagree. `settings.font` is a host override and is respected verbatim — pass a
813
- family you have loaded yourself, or a full stack, and the SDK uses it as-is.
886
+ The selected family is expanded into a full CSS stack with a
887
+ generic fallback (`Times New Roman` becomes `"Times New Roman", Times, serif`). A stored value
888
+ that is no longer offered renders as Arial, so the console and the notice can never disagree.
814
889
 
815
890
  **Available families.** One is a self-hosted webfont — Montserrat — and five are system families
816
891
  needing no download: Arial, Georgia, Times New Roman, Trebuchet MS, Verdana. The catalogue is
@@ -888,7 +963,7 @@ import { RedactoPrivacyCenter } from "@redacto.io/consent-sdk-react/privacy-cent
888
963
  slug="acme-co"
889
964
  accessToken={accessToken}
890
965
  refreshToken={refreshToken}
891
- theme="light"
966
+ settings={{ theme: "glass" }}
892
967
  initialPage="consent-manager"
893
968
  onError={(error) => {
894
969
  console.error(error);
@@ -907,17 +982,28 @@ import { RedactoPrivacyCenter } from "@redacto.io/consent-sdk-react/privacy-cent
907
982
  | `accessToken` | `string` | Yes | - | JWT access token |
908
983
  | `refreshToken` | `string` | Yes | - | JWT refresh token |
909
984
  | `onError` | `(error: Error) => boolean` | Yes | - | Error handler; return `true` if handled |
910
- | `theme` | `"light" \| "dark"` | No | `"light"` | Theme variant |
985
+ | `settings` | `{ theme?: "classic" \| "glass" }` | No | - | Presentation options; `theme` picks the visual style (see [Theme](#privacy-center-appearance)). Colours always come from workspace branding |
911
986
  | `initialPage` | `"consent-manager" \| "form" \| "activity" \| "case-details"` | No | `"consent-manager"` | Page to render first |
912
987
  | `onBack` | `"back" \| "signout"` | No | - | Behaviour of the navbar back/signout control |
913
988
 
989
+ <a id="privacy-center-appearance"></a>
990
+
991
+ ### Theme
992
+
993
+ `settings.theme` picks the visual style; colours, logo and brand name still come from the workspace's branding.
994
+
995
+ - **`classic`** (default): the standard look.
996
+ - **`glass`**: frosted, translucent surfaces over a soft wash of the brand colour, pill-shaped controls and motion. On phones, dialogs and the navigation menu rise as bottom sheets; on wider screens dialogs float as centred cards. Motion respects `prefers-reduced-motion`.
997
+
998
+ Unknown values fall back to `classic`. When composing `PrivacyCenterLayout` yourself, pass `settings={{ theme: "glass" }}` to it directly.
999
+
914
1000
  ### Composable Pages and Layout
915
1001
 
916
1002
  If you want to compose your own shell (e.g. embed the Privacy Center inside an existing app chrome), import the page-level building blocks instead of the certified component:
917
1003
 
918
1004
  | Export | Purpose |
919
1005
  | ----------------------------------- | ------------------------------------------------------------------------ |
920
- | `PrivacyCenterLayout` | Outer chrome (navbar, sidebar, footer, theme) |
1006
+ | `PrivacyCenterLayout` | Outer chrome (navbar, sidebar, footer); accepts `settings.theme` |
921
1007
  | `PrivacyCenterHomePage` | Default home that switches between the pages below |
922
1008
  | `PrivacyCenterConsentManagerPage` | "Manage Consents" view |
923
1009
  | `PrivacyCenterFormPage` | DSR / grievance form |