create-ncblock 0.0.34 → 0.0.36

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ncblock",
3
- "version": "0.0.34",
3
+ "version": "0.0.36",
4
4
  "description": "Create a Notion custom view block project.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,8 +15,9 @@ That writes `custom_blocks.json`, `.notion/target.json`, and PATCHes any blocks
15
15
  ## Talking to the host
16
16
 
17
17
  - Always use the React hooks from `ncblock/react`. Never call `window.parent.postMessage` directly — the SDK owns the protocol.
18
- - Render app code inside `<NotionCustomBlock>` so the handshake completes before hooks run.
19
- - `<NotionCustomBlock>` runs `useCustomBlockAutoResize` for you by default — no extra wiring needed. Pass `autoResize={false}` for full-bleed views.
18
+ - Render app code inside `<NotionCustomBlock>` so the handshake completes before hooks like `useTheme` or `useBlockId` run.
19
+
20
+ `<NotionCustomBlock>` runs `useCustomBlockAutoResize` for you by default — no extra wiring needed. Pass `autoResize={false}` for full-bleed views. Read `node_modules/ncblock/README.md` and the `.d.ts` files for current APIs and signatures.
20
21
 
21
22
  ## Sizing
22
23
 
@@ -49,7 +50,7 @@ Two options:
49
50
 
50
51
  - `node_modules/ncblock/README.md` — landing page with a TOC into the per-category docs below.
51
52
  - `node_modules/ncblock/docs/lifecycle.md` — `<NotionCustomBlock>`, init, sizing, auto-resize.
52
- - `node_modules/ncblock/docs/context.md` — `useCustomBlockContext`, `useTheme`.
53
+ - `node_modules/ncblock/docs/block-location.md` — `useBlockId`, `useParent`, `usePage`, `useTheme`.
53
54
  - `node_modules/ncblock/docs/data-sources.md` — `useDataSource`, row/property/date types, worked example.
54
55
  - `node_modules/ncblock/docs/pages.md` — `pages.create / get / update / delete`.
55
56
  - `node_modules/ncblock/docs/users.md` — `users.list / get`, `NotionUser`.
package/sdk-version.json CHANGED
@@ -1 +1 @@
1
- {"version":"0.0.32"}
1
+ {"version":"0.0.34"}
@@ -28,9 +28,6 @@ Vite bundles `src/index.tsx` into `dist/`. When embedded in Notion, the SDK hook
28
28
 
29
29
  The debug template includes a message log that intercepts and displays all incoming and outgoing `postMessage` events, making it useful for understanding the Notion host communication protocol.
30
30
 
31
- ### SDK hooks
31
+ ### SDK docs
32
32
 
33
- - **`useCustomBlockContext()`** -- returns `{ customBlockId, parent, page }` describing the block's location in the document tree
34
- - **`useTheme()`** -- returns the host's current theme (`"light"` or `"dark"`)
35
- - **`useManifest()`** -- returns the declared manifest (data-source keys + property declarations)
36
- - **`useDataSource(key)`** -- returns `{ items, collectionSchema, propertySchemasById, propertySchemasByKey, isLoading, hasMore, fetchMore, error }`. Each `item` has `{ id, propertiesById, propertiesByKey }`. The four built-ins (`created_time`, `last_edited_time`, `created_by`, `last_edited_by`) appear in `propertiesById` / `propertySchemasById`, never in the `*ByKey` views.
33
+ This project uses the public `ncblock` React hooks and data source APIs. After installing dependencies, see `node_modules/ncblock/README.md` for the current API reference and links to the per-category docs.
@@ -1,6 +1,6 @@
1
1
  import {
2
+ type NotionBlockId,
2
3
  type NotionCreatePagePosition,
3
- type NotionCustomBlockContext,
4
4
  type NotionDataSourceId,
5
5
  type NotionPage,
6
6
  type NotionPageId,
@@ -8,9 +8,11 @@ import {
8
8
  } from "ncblock"
9
9
  import {
10
10
  NotionCustomBlock,
11
+ useBlockId,
11
12
  useCurrentUser,
12
- useCustomBlockContext,
13
13
  useManifest,
14
+ usePage,
15
+ useParent,
14
16
  useTheme,
15
17
  } from "ncblock/react"
16
18
  import React, {
@@ -55,7 +57,9 @@ const metaTextClass =
55
57
  const HOST_NO_READY_ERROR_DELAY_SECONDS = 5
56
58
 
57
59
  function App() {
58
- const ctx = useCustomBlockContext()
60
+ const blockId = useBlockId()
61
+ const parent = useParent()
62
+ const page = usePage()
59
63
  const currentUser = useCurrentUser()
60
64
  const hostThemeValue = useTheme()
61
65
  const manifest = useManifest()
@@ -84,11 +88,11 @@ function App() {
84
88
  "--status-color": status.color,
85
89
  } as React.CSSProperties
86
90
 
87
- const contextValue = {
91
+ const blockLocationValue = {
88
92
  theme: hostThemeValue,
89
- customBlockId: ctx?.customBlockId,
90
- parent: ctx?.parent,
91
- page: ctx?.page,
93
+ blockId,
94
+ parent,
95
+ page,
92
96
  currentUser,
93
97
  manifest,
94
98
  }
@@ -158,32 +162,36 @@ function App() {
158
162
  </div>
159
163
  </CollapsibleCard>
160
164
 
161
- {/* Context state */}
165
+ {/* Init state */}
162
166
  <CollapsibleCard
163
167
  label="Init payload"
164
168
  headerExtra={
165
169
  <span className={metaTextClass}>
166
- {Object.keys(contextValue).length} keys
170
+ {Object.keys(blockLocationValue).length} keys
167
171
  </span>
168
172
  }
169
173
  headerActions={
170
174
  <IconButton
171
- label="Copy context JSON"
172
- onClick={() => copy(serializeForCopy(contextValue))}
175
+ label="Copy init JSON"
176
+ onClick={() => copy(serializeForCopy(blockLocationValue))}
173
177
  >
174
178
  <CopyIcon />
175
179
  </IconButton>
176
180
  }
177
181
  >
178
182
  <JsonPanel
179
- value={contextValue}
183
+ value={blockLocationValue}
180
184
  onCopy={copy}
181
185
  defaultExpandedDepth={2}
182
186
  />
183
187
  </CollapsibleCard>
184
188
 
185
189
  {/* Create page */}
186
- <CreatePageCard context={ctx} dataSourceKeys={dataSourceKeys} />
190
+ <CreatePageCard
191
+ blockId={blockId}
192
+ currentPage={page}
193
+ dataSourceKeys={dataSourceKeys}
194
+ />
187
195
 
188
196
  {/* Send message */}
189
197
  <SendMessageCard onSend={send} />
@@ -1655,7 +1663,8 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
1655
1663
  }
1656
1664
 
1657
1665
  type CreatePageCardProps = {
1658
- context: NotionCustomBlockContext | undefined
1666
+ blockId: NotionBlockId | undefined
1667
+ currentPage: { id: NotionPageId } | undefined
1659
1668
  dataSourceKeys: string[]
1660
1669
  }
1661
1670
 
@@ -1666,7 +1675,7 @@ type CreatePagePreset = {
1666
1675
  }
1667
1676
 
1668
1677
  function presetPositions(
1669
- customBlockId: string | undefined,
1678
+ customBlockId: NotionBlockId | undefined,
1670
1679
  ): CreatePagePreset[] {
1671
1680
  const presets: CreatePagePreset[] = [
1672
1681
  {
@@ -1775,7 +1784,7 @@ function pageIconFromInput(raw: string): NotionPage["icon"] | undefined {
1775
1784
  /**
1776
1785
  * Buttons that exercise `sdk.pages.create` at each of the supported positions. Every preset creates
1777
1786
  * a page whose `parent.page_id` is the nearest page ancestor. `position` demonstrates append,
1778
- * prepend, and inserting directly above or below the custom block via `context.customBlockId`.
1787
+ * prepend, and inserting directly above or below the custom block via `useBlockId()`.
1779
1788
  *
1780
1789
  * Two extra affordances exercise the data-source-backed parents:
1781
1790
  * - A free-form input accepts a data source ID and uses `parent: { type: "data_source_id", ... }`
@@ -1784,34 +1793,38 @@ function pageIconFromInput(raw: string): NotionPage["icon"] | undefined {
1784
1793
  * SDK resolve the key to the configured data source ID locally before sending the request to the
1785
1794
  * Notion host.
1786
1795
  */
1787
- function CreatePageCard({ context, dataSourceKeys }: CreatePageCardProps) {
1796
+ function CreatePageCard({
1797
+ blockId,
1798
+ currentPage,
1799
+ dataSourceKeys,
1800
+ }: CreatePageCardProps) {
1788
1801
  const [status, setStatus] = useState<string | null>(null)
1789
1802
  const [busy, setBusy] = useState(false)
1790
1803
  const [dataSourceId, setDataSourceId] = useState("")
1791
1804
  const [pageId, setPageId] = useState("")
1792
1805
  const [trackedPages, setTrackedPages] = useState<TrackedPage[]>([])
1793
- const presets = presetPositions(context?.customBlockId)
1794
- const disabled = context === undefined || busy
1806
+ const presets = presetPositions(blockId)
1807
+ const disabled = currentPage === undefined || busy
1795
1808
  const trimmedDataSourceId = dataSourceId.trim()
1796
1809
  const dataSourceDisabled = disabled || trimmedDataSourceId === ""
1797
1810
  const trimmedPageId = pageId.trim()
1798
1811
  const fetchDisabled = busy || trimmedPageId === ""
1799
1812
 
1800
1813
  useEffect(() => {
1801
- if (context?.page.id && pageId === "") {
1802
- setPageId(context.page.id)
1814
+ if (currentPage !== undefined && pageId === "") {
1815
+ setPageId(currentPage.id)
1803
1816
  }
1804
- }, [context?.page.id, pageId])
1817
+ }, [currentPage, pageId])
1805
1818
 
1806
1819
  const handleCreate = async (preset: CreatePagePreset) => {
1807
- if (context === undefined || busy) {
1820
+ if (currentPage === undefined || busy) {
1808
1821
  return
1809
1822
  }
1810
1823
  setBusy(true)
1811
1824
  setStatus(`Creating (${preset.label})\u2026`)
1812
1825
  const title = `New page (${preset.label.toLowerCase()}) ${new Date().toLocaleTimeString()}`
1813
1826
  const result = await pages.create({
1814
- parent: { type: "page_id", page_id: context.page.id },
1827
+ parent: { type: "page_id", page_id: currentPage.id },
1815
1828
  properties: {
1816
1829
  title: {
1817
1830
  id: "title",
@@ -1825,13 +1838,13 @@ function CreatePageCard({ context, dataSourceKeys }: CreatePageCardProps) {
1825
1838
  setTrackedPages(prev => trackPage(prev, result.page))
1826
1839
  setStatus(`\u2713 ${preset.label}: ${result.page.id}`)
1827
1840
  } else {
1828
- setStatus(`\u2717 ${preset.label}: ${result.error}`)
1841
+ setStatus(`\u2717 ${preset.label}: ${result.error.message}`)
1829
1842
  }
1830
1843
  setBusy(false)
1831
1844
  }
1832
1845
 
1833
1846
  const handleCreateInDataSource = async () => {
1834
- if (context === undefined || busy || trimmedDataSourceId === "") {
1847
+ if (currentPage === undefined || busy || trimmedDataSourceId === "") {
1835
1848
  return
1836
1849
  }
1837
1850
  setBusy(true)
@@ -1854,13 +1867,13 @@ function CreatePageCard({ context, dataSourceKeys }: CreatePageCardProps) {
1854
1867
  setTrackedPages(prev => trackPage(prev, result.page))
1855
1868
  setStatus(`\u2713 Data source: ${result.page.id}`)
1856
1869
  } else {
1857
- setStatus(`\u2717 Data source: ${result.error}`)
1870
+ setStatus(`\u2717 Data source: ${result.error.message}`)
1858
1871
  }
1859
1872
  setBusy(false)
1860
1873
  }
1861
1874
 
1862
1875
  const handleCreateForKey = async (key: string) => {
1863
- if (context === undefined || busy) {
1876
+ if (disabled) {
1864
1877
  return
1865
1878
  }
1866
1879
  setBusy(true)
@@ -1880,7 +1893,7 @@ function CreatePageCard({ context, dataSourceKeys }: CreatePageCardProps) {
1880
1893
  setTrackedPages(prev => trackPage(prev, result.page))
1881
1894
  setStatus(`\u2713 Key "${key}": ${result.page.id}`)
1882
1895
  } else {
1883
- setStatus(`\u2717 Key "${key}": ${result.error}`)
1896
+ setStatus(`\u2717 Key "${key}": ${result.error.message}`)
1884
1897
  }
1885
1898
  setBusy(false)
1886
1899
  }
@@ -1896,7 +1909,7 @@ function CreatePageCard({ context, dataSourceKeys }: CreatePageCardProps) {
1896
1909
  setTrackedPages(prev => trackPage(prev, result.page))
1897
1910
  setStatus(`\u2713 Loaded ${result.page.id}`)
1898
1911
  } else {
1899
- setStatus(`\u2717 Fetch failed: ${result.error}`)
1912
+ setStatus(`\u2717 Fetch failed: ${result.error.message}`)
1900
1913
  }
1901
1914
  setBusy(false)
1902
1915
  }
@@ -1912,7 +1925,7 @@ function CreatePageCard({ context, dataSourceKeys }: CreatePageCardProps) {
1912
1925
  setTrackedPages(prev => trackPage(prev, result.page))
1913
1926
  setStatus(`\u2713 Refreshed ${result.page.id}`)
1914
1927
  } else {
1915
- setStatus(`\u2717 Refresh failed: ${result.error}`)
1928
+ setStatus(`\u2717 Refresh failed: ${result.error.message}`)
1916
1929
  }
1917
1930
  setBusy(false)
1918
1931
  }
@@ -1961,7 +1974,7 @@ function CreatePageCard({ context, dataSourceKeys }: CreatePageCardProps) {
1961
1974
  setTrackedPages(prev => trackPage(prev, result.page))
1962
1975
  setStatus(`\u2713 Saved ${result.page.id}`)
1963
1976
  } else {
1964
- setStatus(`\u2717 Save failed: ${result.error}`)
1977
+ setStatus(`\u2717 Save failed: ${result.error.message}`)
1965
1978
  }
1966
1979
  setBusy(false)
1967
1980
  }
@@ -1977,7 +1990,7 @@ function CreatePageCard({ context, dataSourceKeys }: CreatePageCardProps) {
1977
1990
  setTrackedPages(prev => trackPage(prev, result.page))
1978
1991
  setStatus(`\u2713 Deleted ${result.page.id}`)
1979
1992
  } else {
1980
- setStatus(`\u2717 Delete failed: ${result.error}`)
1993
+ setStatus(`\u2717 Delete failed: ${result.error.message}`)
1981
1994
  }
1982
1995
  setBusy(false)
1983
1996
  }
@@ -2047,7 +2060,7 @@ function CreatePageCard({ context, dataSourceKeys }: CreatePageCardProps) {
2047
2060
  type="text"
2048
2061
  value={pageId}
2049
2062
  onChange={event => setPageId(event.target.value)}
2050
- placeholder={context?.page.id ?? "page_id"}
2063
+ placeholder={currentPage?.id ?? "page_id"}
2051
2064
  spellCheck={false}
2052
2065
  className="min-w-0 flex-1 rounded-md border border-(--border) bg-(--app-bg) px-2 py-1 font-mono text-[11px] outline-none transition-colors focus:border-(--foreground)"
2053
2066
  />
@@ -47,9 +47,6 @@ Example row shape:
47
47
 
48
48
  If the mapped collection is missing any of those fields, the template shows a setup hint and falls back to built-in sample data so you can still preview the chart locally.
49
49
 
50
- ## SDK hooks
50
+ ## SDK docs
51
51
 
52
- - **`useCustomBlockContext()`** -- returns `{ customBlockId, parent, page }` describing the block's location in the document tree
53
- - **`useTheme()`** -- returns the host's current theme (`"light"` or `"dark"`)
54
- - **`useManifest()`** -- returns the declared manifest (data-source keys + property declarations)
55
- - **`useDataSource(key)`** -- returns `{ items, collectionSchema, propertySchemasById, propertySchemasByKey, isLoading, hasMore, fetchMore, error }`. Each `item` has `{ id, propertiesById, propertiesByKey }`. The four built-ins (`created_time`, `last_edited_time`, `created_by`, `last_edited_by`) appear in `propertiesById` / `propertySchemasById`, never in the `*ByKey` views.
52
+ This project uses the public `ncblock` React hooks and data source APIs. After installing dependencies, see `node_modules/ncblock/README.md` for the current API reference and links to the per-category docs.
@@ -33,7 +33,11 @@ function makeFakeItem(
33
33
  propertiesByKey: properties,
34
34
  update: async () => ({
35
35
  status: "error",
36
- error: "Sample rows are read-only",
36
+ error: {
37
+ code: "update_page_failed",
38
+ message: "Sample rows are read-only",
39
+ isRetryable: false,
40
+ },
37
41
  }),
38
42
  }
39
43
  }
@@ -515,7 +519,7 @@ function App() {
515
519
  items={items}
516
520
  isUsingFallbackData={isUsingFallbackData}
517
521
  analysis={analysis}
518
- queryError={query.error}
522
+ queryError={query.error?.message}
519
523
  hasMore={query.hasMore}
520
524
  isLoading={query.isLoading}
521
525
  onFetchMore={query.fetchMore}
@@ -35,9 +35,6 @@ string arrays, and relations. It also includes search, column visibility
35
35
  controls, density switching, and relation pills that render `-> title` when a
36
36
  related page is loaded or `-> uuid` when it is not.
37
37
 
38
- ## SDK hooks
38
+ ## SDK docs
39
39
 
40
- - **`useCustomBlockContext()`** -- returns `{ customBlockId, parent, page }` describing the block's location in the document tree
41
- - **`useTheme()`** -- returns the host's current theme (`"light"` or `"dark"`)
42
- - **`useManifest()`** -- returns the declared manifest (data-source keys + property declarations)
43
- - **`useDataSource(key)`** -- returns `{ items, collectionSchema, propertySchemasById, propertySchemasByKey, isLoading, hasMore, fetchMore, error }`. Each `item` has `{ id, propertiesById, propertiesByKey }`. The four built-ins (`created_time`, `last_edited_time`, `created_by`, `last_edited_by`) appear in `propertiesById` / `propertySchemasById`, never in the `*ByKey` views.
40
+ This project uses the public `ncblock` React hooks and data source APIs. After installing dependencies, see `node_modules/ncblock/README.md` for the current API reference and links to the per-category docs.
@@ -1162,7 +1162,7 @@ function DataWorkspace(props: {
1162
1162
  })
1163
1163
  return
1164
1164
  }
1165
- setUpdateStatus({ type: "error", message: result.error })
1165
+ setUpdateStatus({ type: "error", message: result.error.message })
1166
1166
  } catch (error) {
1167
1167
  setUpdateStatus({
1168
1168
  type: "error",
@@ -1212,7 +1212,7 @@ function DataWorkspace(props: {
1212
1212
  setCreatingDraft(emptyDraftByKey(writableColumns))
1213
1213
  return
1214
1214
  }
1215
- setCreateStatus({ type: "error", message: result.error })
1215
+ setCreateStatus({ type: "error", message: result.error.message })
1216
1216
  } catch (error) {
1217
1217
  setCreateStatus({
1218
1218
  type: "error",
@@ -1803,7 +1803,7 @@ function App() {
1803
1803
  onFetchMore={query.fetchMore}
1804
1804
  isUsingFallbackData={isUsingFallbackData}
1805
1805
  isCollectionEmpty={isCollectionEmpty}
1806
- queryError={query.error}
1806
+ queryError={query.error?.message}
1807
1807
  />
1808
1808
  </div>
1809
1809
  </div>
@@ -82,7 +82,11 @@ function makeSampleRow(
82
82
  propertiesByKey: properties,
83
83
  update: async () => ({
84
84
  status: "error",
85
- error: "Sample rows are read-only",
85
+ error: {
86
+ code: "update_page_failed",
87
+ message: "Sample rows are read-only",
88
+ isRetryable: false,
89
+ },
86
90
  }),
87
91
  }
88
92
  }