@hadoku/task-ui-components 4.22.3 → 4.22.5

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.
@@ -112,12 +112,6 @@
112
112
  color: var(--color-text);
113
113
  }
114
114
 
115
- /* Divider above the optional app-specific settings section. */
116
- .settings-popout__app {
117
- border-top: 1px solid var(--color-border);
118
- padding-top: 12px;
119
- }
120
-
121
115
  .settings-popout__header {
122
116
  font-weight: 600;
123
117
  font-size: 0.95rem;
@@ -30,13 +30,13 @@
30
30
  * // once, at the app root:
31
31
  * <HadokuThemeRoot>
32
32
  * <AppHeader title="Print Tool" status={<ApiStatus status={apiStatus} />}>
33
- * <MyAppPreferences /> // optional: appended AFTER the canonical rows
33
+ * <MyAppPreferences /> // optional: the "App" tab, after the site's tabs
34
34
  * </AppHeader>
35
35
  * </HadokuThemeRoot>
36
36
  * ```
37
37
  */
38
38
  import React from 'react';
39
- import { type ConnectedSettingsProps } from './ConnectedSettings';
39
+ import { type AppSettingsTab, type ConnectedSettingsProps } from './ConnectedSettings';
40
40
  export interface AppHeaderProps {
41
41
  /** Left-aligned header title. A string is wrapped in an <h1>; pass a node for
42
42
  * custom markup (e.g. a clickable title button). */
@@ -48,14 +48,17 @@ export interface AppHeaderProps {
48
48
  * `name` exist because an app behind a path-prefixed shim may not be able to
49
49
  * reach `/session/whoami` (conjure), NOT as a styling or layout hook. */
50
50
  settingsProps?: ConnectedSettingsProps;
51
- /** THE app-specific extension point. Rendered inside the settings popout as a
52
- * final section, under the four canonical rows. Put your app's own
53
- * preferences here — checkboxes, selects, whatever it needs; this slot is
54
- * deliberately unconstrained. What it cannot do is alter the rows above it. */
51
+ /** THE app-specific extension point. Rendered inside the settings popout as
52
+ * one "App" tab, after the site's own tabs. Put your app's own preferences
53
+ * here — checkboxes, selects, whatever it needs; this slot is deliberately
54
+ * unconstrained. What it cannot do is alter the site's tabs. */
55
55
  children?: React.ReactNode;
56
+ /** The same, split into tabs of the app's own: one per entry, after the
57
+ * "App" tab if `children` is also given. See AppSettingsTab. */
58
+ appTabs?: AppSettingsTab[];
56
59
  /** Extra class on the <header> root. Layout only — it cannot reach the
57
60
  * controls, which own their own markup. */
58
61
  className?: string;
59
62
  }
60
- export declare function AppHeader({ title, status, settingsProps, children, className }: AppHeaderProps): React.JSX.Element;
63
+ export declare function AppHeader({ title, status, settingsProps, children, appTabs, className }: AppHeaderProps): React.JSX.Element;
61
64
  //# sourceMappingURL=AppHeader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppHeader.d.ts","sourceRoot":"","sources":["../../src/components/AppHeader.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAGpF,MAAM,WAAW,cAAc;IAC7B;yDACqD;IACrD,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB;gFAC4E;IAC5E,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB;;8EAE0E;IAC1E,aAAa,CAAC,EAAE,sBAAsB,CAAA;IACtC;;;oFAGgF;IAChF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B;gDAC4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,MAAM,EACN,aAAa,EACb,QAAQ,EACR,SAAc,EACf,EAAE,cAAc,qBAkBhB"}
1
+ {"version":3,"file":"AppHeader.d.ts","sourceRoot":"","sources":["../../src/components/AppHeader.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC5B,MAAM,qBAAqB,CAAA;AAG5B,MAAM,WAAW,cAAc;IAC7B;yDACqD;IACrD,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB;gFAC4E;IAC5E,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB;;8EAE0E;IAC1E,aAAa,CAAC,EAAE,sBAAsB,CAAA;IACtC;;;qEAGiE;IACjE,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B;qEACiE;IACjE,OAAO,CAAC,EAAE,cAAc,EAAE,CAAA;IAC1B;gDAC4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,MAAM,EACN,aAAa,EACb,QAAQ,EACR,OAAO,EACP,SAAc,EACf,EAAE,cAAc,qBAoBhB"}
@@ -6,6 +6,7 @@ function AppHeader({
6
6
  status,
7
7
  settingsProps,
8
8
  children,
9
+ appTabs,
9
10
  className = ""
10
11
  }) {
11
12
  return /* @__PURE__ */ jsxs("header", { className: `app-header ${className}`.trim(), children: [
@@ -13,7 +14,7 @@ function AppHeader({
13
14
  /* @__PURE__ */ jsxs("div", { className: "app-header__actions", children: [
14
15
  status,
15
16
  /* @__PURE__ */ jsx(HadokuThemePicker, {}),
16
- /* @__PURE__ */ jsx(ConnectedSettings, { ...settingsProps, children })
17
+ /* @__PURE__ */ jsx(ConnectedSettings, { ...settingsProps, appTabs, children })
17
18
  ] })
18
19
  ] });
19
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AppHeader.js","sources":["../../src/components/AppHeader.tsx"],"sourcesContent":["/**\n * AppHeader — the ecosystem-standard top bar for every hadoku.me app.\n *\n * Enforces the shared contract so child apps stop drifting:\n * [ title (left) ] ————— <space> ————— [ status? · ThemePicker · Settings gear ] (right)\n *\n * Everything BELOW the header is the app's own concern. The header owns the\n * title, and it OWNS both right-hand controls outright — it renders the theme\n * picker and the settings gear itself. Neither is a prop.\n *\n * WHY THEY ARE NOT PROPS ANY MORE\n * -------------------------------\n * `themePicker?: React.ReactNode` was an open hole: a slot that accepts a node\n * accepts ANY node, so \"every app uses the same picker\" was a convention, and\n * conventions drift. They did — one app passed a raw `<ThemePicker>` with its\n * own `isOpen` state and a debug logger wired into `getThemeIcon`, and eight\n * apps each kept a hand-copied `useTheme` hook to feed it. Those copies had\n * already diverged on real behaviour (only one wrote `localStorage`, so the\n * rest lost the theme on browser restart and flashed a default on next paint).\n *\n * The control is now rendered here, from `useHadokuTheme()`. An app cannot\n * substitute, restyle or omit it. What an app CAN do is inject its own\n * preferences — see `children`.\n *\n * @example\n * ```tsx\n * import { AppHeader } from '@wolffm/task-ui-components'\n * import { HadokuThemeRoot } from '@wolffm/themes'\n *\n * // once, at the app root:\n * <HadokuThemeRoot>\n * <AppHeader title=\"Print Tool\" status={<ApiStatus status={apiStatus} />}>\n * <MyAppPreferences /> // optional: appended AFTER the canonical rows\n * </AppHeader>\n * </HadokuThemeRoot>\n * ```\n */\nimport React from 'react'\nimport { ConnectedSettings, type ConnectedSettingsProps } from './ConnectedSettings'\nimport { HadokuThemePicker } from './HadokuThemePicker'\n\nexport interface AppHeaderProps {\n /** Left-aligned header title. A string is wrapped in an <h1>; pass a node for\n * custom markup (e.g. a clickable title button). */\n title: React.ReactNode\n /** Optional status/extra node shown left of the theme + settings controls\n * (e.g. an \"API Online\" indicator). Acceptable per the header contract. */\n status?: React.ReactNode\n /** Identity hints for the settings popout. Narrow on purpose: `userType` and\n * `name` exist because an app behind a path-prefixed shim may not be able to\n * reach `/session/whoami` (conjure), NOT as a styling or layout hook. */\n settingsProps?: ConnectedSettingsProps\n /** THE app-specific extension point. Rendered inside the settings popout as a\n * final section, under the four canonical rows. Put your app's own\n * preferences here — checkboxes, selects, whatever it needs; this slot is\n * deliberately unconstrained. What it cannot do is alter the rows above it. */\n children?: React.ReactNode\n /** Extra class on the <header> root. Layout only — it cannot reach the\n * controls, which own their own markup. */\n className?: string\n}\n\nexport function AppHeader({\n title,\n status,\n settingsProps,\n children,\n className = ''\n}: AppHeaderProps) {\n // No useHadokuTheme() call here: <HadokuThemePicker> reads the context and\n // throws its own actionable error when the app root was never wrapped, so a\n // second read would only duplicate that.\n return (\n <header className={`app-header ${className}`.trim()}>\n {typeof title === 'string' ? (\n <h1 className=\"app-header__title\">{title}</h1>\n ) : (\n <div className=\"app-header__title\">{title}</div>\n )}\n <div className=\"app-header__actions\">\n {status}\n <HadokuThemePicker />\n <ConnectedSettings {...settingsProps}>{children}</ConnectedSettings>\n </div>\n </header>\n )\n}\n"],"names":[],"mappings":";;;AA8DO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAAmB;AAIjB,8BACG,UAAA,EAAO,WAAW,cAAc,SAAS,GAAG,QAC1C,UAAA;AAAA,IAAA,OAAO,UAAU,WAChB,oBAAC,MAAA,EAAG,WAAU,qBAAqB,UAAA,MAAA,CAAM,IAEzC,oBAAC,OAAA,EAAI,WAAU,qBAAqB,UAAA,OAAM;AAAA,IAE5C,qBAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,MAAA;AAAA,0BACA,mBAAA,EAAkB;AAAA,MACnB,oBAAC,mBAAA,EAAmB,GAAG,eAAgB,SAAA,CAAS;AAAA,IAAA,EAAA,CAClD;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"AppHeader.js","sources":["../../src/components/AppHeader.tsx"],"sourcesContent":["/**\n * AppHeader — the ecosystem-standard top bar for every hadoku.me app.\n *\n * Enforces the shared contract so child apps stop drifting:\n * [ title (left) ] ————— <space> ————— [ status? · ThemePicker · Settings gear ] (right)\n *\n * Everything BELOW the header is the app's own concern. The header owns the\n * title, and it OWNS both right-hand controls outright — it renders the theme\n * picker and the settings gear itself. Neither is a prop.\n *\n * WHY THEY ARE NOT PROPS ANY MORE\n * -------------------------------\n * `themePicker?: React.ReactNode` was an open hole: a slot that accepts a node\n * accepts ANY node, so \"every app uses the same picker\" was a convention, and\n * conventions drift. They did — one app passed a raw `<ThemePicker>` with its\n * own `isOpen` state and a debug logger wired into `getThemeIcon`, and eight\n * apps each kept a hand-copied `useTheme` hook to feed it. Those copies had\n * already diverged on real behaviour (only one wrote `localStorage`, so the\n * rest lost the theme on browser restart and flashed a default on next paint).\n *\n * The control is now rendered here, from `useHadokuTheme()`. An app cannot\n * substitute, restyle or omit it. What an app CAN do is inject its own\n * preferences — see `children`.\n *\n * @example\n * ```tsx\n * import { AppHeader } from '@wolffm/task-ui-components'\n * import { HadokuThemeRoot } from '@wolffm/themes'\n *\n * // once, at the app root:\n * <HadokuThemeRoot>\n * <AppHeader title=\"Print Tool\" status={<ApiStatus status={apiStatus} />}>\n * <MyAppPreferences /> // optional: the \"App\" tab, after the site's tabs\n * </AppHeader>\n * </HadokuThemeRoot>\n * ```\n */\nimport React from 'react'\nimport {\n ConnectedSettings,\n type AppSettingsTab,\n type ConnectedSettingsProps\n} from './ConnectedSettings'\nimport { HadokuThemePicker } from './HadokuThemePicker'\n\nexport interface AppHeaderProps {\n /** Left-aligned header title. A string is wrapped in an <h1>; pass a node for\n * custom markup (e.g. a clickable title button). */\n title: React.ReactNode\n /** Optional status/extra node shown left of the theme + settings controls\n * (e.g. an \"API Online\" indicator). Acceptable per the header contract. */\n status?: React.ReactNode\n /** Identity hints for the settings popout. Narrow on purpose: `userType` and\n * `name` exist because an app behind a path-prefixed shim may not be able to\n * reach `/session/whoami` (conjure), NOT as a styling or layout hook. */\n settingsProps?: ConnectedSettingsProps\n /** THE app-specific extension point. Rendered inside the settings popout as\n * one \"App\" tab, after the site's own tabs. Put your app's own preferences\n * here — checkboxes, selects, whatever it needs; this slot is deliberately\n * unconstrained. What it cannot do is alter the site's tabs. */\n children?: React.ReactNode\n /** The same, split into tabs of the app's own: one per entry, after the\n * \"App\" tab if `children` is also given. See AppSettingsTab. */\n appTabs?: AppSettingsTab[]\n /** Extra class on the <header> root. Layout only — it cannot reach the\n * controls, which own their own markup. */\n className?: string\n}\n\nexport function AppHeader({\n title,\n status,\n settingsProps,\n children,\n appTabs,\n className = ''\n}: AppHeaderProps) {\n // No useHadokuTheme() call here: <HadokuThemePicker> reads the context and\n // throws its own actionable error when the app root was never wrapped, so a\n // second read would only duplicate that.\n return (\n <header className={`app-header ${className}`.trim()}>\n {typeof title === 'string' ? (\n <h1 className=\"app-header__title\">{title}</h1>\n ) : (\n <div className=\"app-header__title\">{title}</div>\n )}\n <div className=\"app-header__actions\">\n {status}\n <HadokuThemePicker />\n <ConnectedSettings {...settingsProps} appTabs={appTabs}>\n {children}\n </ConnectedSettings>\n </div>\n </header>\n )\n}\n"],"names":[],"mappings":";;;AAqEO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAAmB;AAIjB,8BACG,UAAA,EAAO,WAAW,cAAc,SAAS,GAAG,QAC1C,UAAA;AAAA,IAAA,OAAO,UAAU,WAChB,oBAAC,MAAA,EAAG,WAAU,qBAAqB,UAAA,MAAA,CAAM,IAEzC,oBAAC,OAAA,EAAI,WAAU,qBAAqB,UAAA,OAAM;AAAA,IAE5C,qBAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,MAAA;AAAA,0BACA,mBAAA,EAAkB;AAAA,MACnB,oBAAC,mBAAA,EAAmB,GAAG,eAAe,SACnC,SAAA,CACH;AAAA,IAAA,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
@@ -8,6 +8,10 @@
8
8
  * - global content-visibility level (tiered pill → PUT /prefs/api/v1/content-level)
9
9
  * - switch key (an inline sign-in form, on the site's own sign-in client)
10
10
  *
11
+ * Those are grouped into tabs (Profile, Content, Account), followed by the
12
+ * app's own: `children` as one "App" tab, `appTabs` as one tab each. The open
13
+ * tab is remembered per user and per app (useSettingsTab, @wolffm/themes).
14
+ *
11
15
  * "Connected" (parallel to ConnectedThemePicker): it self-wires to the
12
16
  * hadoku.me edge-router via same-origin fetches (see lib/settingsClient), so
13
17
  * dropping `<ConnectedSettings />` into any app under hadoku.me needs zero
@@ -41,14 +45,23 @@ export interface ConnectedSettingsProps {
41
45
  name?: string | null;
42
46
  /** Notify the host (e.g. a "Signed in as …" label) of a rename. */
43
47
  onNameChange?: (name: string | null) => void;
44
- /** App-specific settings rendered as a final section in the same popout, so
45
- * an app with its own preferences keeps ONE unified gear instead of a second
46
- * control. Shown under an "App preferences" divider.
48
+ /** App-specific settings as ONE tab, labelled "App", after the site's own
49
+ * tabs — so an app with its own preferences keeps one unified gear instead
50
+ * of a second control. For more than one section, use `appTabs`.
47
51
  *
48
52
  * This slot is deliberately unconstrained — put whatever the app needs in
49
- * it. The constraint is only that it lands AFTER the four canonical rows and
50
- * cannot change them. */
53
+ * it. The constraint is only that it cannot change the site's tabs. */
51
54
  children?: React.ReactNode;
55
+ /** App-specific settings as tabs of their own, after `children`'s "App" tab
56
+ * if both are given. `id` is stable and unique within the app: the last-open
57
+ * tab is remembered by it. `render` runs only while its tab is open. */
58
+ appTabs?: AppSettingsTab[];
59
+ }
60
+ /** One app-contributed tab in the settings popout. */
61
+ export interface AppSettingsTab {
62
+ id: string;
63
+ label: string;
64
+ render: () => React.ReactNode;
52
65
  }
53
- export declare function ConnectedSettings({ userType: userTypeProp, name: nameProp, onNameChange, children }: ConnectedSettingsProps): React.JSX.Element;
66
+ export declare function ConnectedSettings({ userType: userTypeProp, name: nameProp, onNameChange, children, appTabs }: ConnectedSettingsProps): React.JSX.Element;
54
67
  //# sourceMappingURL=ConnectedSettings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectedSettings.d.ts","sourceRoot":"","sources":["../../src/components/ConnectedSettings.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAmD,MAAM,OAAO,CAAA;AAGvE,OAAO,EAWL,KAAK,IAAI,EACV,MAAM,uBAAuB,CAAA;AAC9B,OAAO,mBAAmB,CAAA;AAE1B,MAAM,WAAW,sBAAsB;IACrC;;;;;;+EAM2E;IAC3E,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,mEAAmE;IACnE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC5C;;;;;;8BAM0B;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AA0ED,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,QAAQ,EACd,YAAY,EACZ,QAAQ,EACT,EAAE,sBAAsB,qBAmpBxB"}
1
+ {"version":3,"file":"ConnectedSettings.d.ts","sourceRoot":"","sources":["../../src/components/ConnectedSettings.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAA0D,MAAM,OAAO,CAAA;AAI9E,OAAO,EAWL,KAAK,IAAI,EACV,MAAM,uBAAuB,CAAA;AAC9B,OAAO,mBAAmB,CAAA;AAE1B,MAAM,WAAW,sBAAsB;IACrC;;;;;;+EAM2E;IAC3E,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,mEAAmE;IACnE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC5C;;;;;4EAKwE;IACxE,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B;;6EAEyE;IACzE,OAAO,CAAC,EAAE,cAAc,EAAE,CAAA;CAC3B;AAED,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,KAAK,CAAC,SAAS,CAAA;CAC9B;AAmID,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,QAAQ,EACd,YAAY,EACZ,QAAQ,EACR,OAAO,EACR,EAAE,sBAAsB,qBAwwBxB"}