noktiq 0.0.0-stage → 0.1.0
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/CONTRIBUTING.md +37 -0
- package/LICENSE +91 -0
- package/README.md +72 -2
- package/SECURITY.md +19 -0
- package/dist/context.d.ts +50 -0
- package/dist/dom.d.ts +36 -0
- package/dist/editor.d.ts +19 -0
- package/dist/identity.d.ts +36 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +7 -0
- package/dist/mascot.d.ts +12 -0
- package/dist/motion.d.ts +6 -0
- package/dist/next.d.ts +3 -0
- package/dist/next.js +51 -0
- package/dist/next.js.map +7 -0
- package/dist/options.d.ts +8 -0
- package/dist/output.d.ts +8 -0
- package/dist/react.d.ts +4 -0
- package/dist/react.js +20 -0
- package/dist/react.js.map +7 -0
- package/dist/selection.d.ts +21 -0
- package/dist/shared-chunk.js +2140 -0
- package/dist/shared-chunk.js.map +7 -0
- package/dist/source.cjs +205 -0
- package/dist/source.d.ts +9 -0
- package/dist/storage.d.ts +25 -0
- package/dist/styles.d.ts +1 -0
- package/dist/vite.d.ts +4 -0
- package/dist/vite.js +194 -0
- package/dist/vite.js.map +7 -0
- package/dist/vue.d.ts +69 -0
- package/dist/vue.js +36 -0
- package/dist/vue.js.map +7 -0
- package/dist/webpack-loader.cjs +34 -0
- package/docs/assets/readme-header.svg +19 -0
- package/docs/guide.tr.md +367 -0
- package/docs/walkthrough-request.md +34 -0
- package/package.json +71 -4
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Contributing to Noktiq
|
|
2
|
+
|
|
3
|
+
Noktiq helps people give coding agents clear visual change requests in React and Vue projects. Bug fixes, reproducible compatibility reports and focused improvements are welcome.
|
|
4
|
+
|
|
5
|
+
## Before starting
|
|
6
|
+
|
|
7
|
+
Open an issue first for a substantial feature, framework integration or UI change. Explain the problem and a concrete example. Keep the existing mascot and interaction design unless a design change has been agreed.
|
|
8
|
+
|
|
9
|
+
For bugs, include the Noktiq/framework/build-tool/browser versions, reproduction steps and expected versus actual behavior. A small repository or code sample is especially useful. Remove credentials, private project code and personal paths from shared examples. Follow [SECURITY.md](SECURITY.md) for vulnerabilities.
|
|
10
|
+
|
|
11
|
+
## Run locally
|
|
12
|
+
|
|
13
|
+
Use a Node version supported by the installed Vite toolchain. From the repository root:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm ci
|
|
17
|
+
npm run build
|
|
18
|
+
npm run dev:react
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Use `npm run dev:vue` in another terminal for the Vue demo. Examples consume `dist`; rebuild after library changes. The [developer guide](docs/guide.tr.md) covers Next, Nuxt, Webpack and browser fixtures.
|
|
22
|
+
|
|
23
|
+
## Before a pull request
|
|
24
|
+
|
|
25
|
+
Keep the change focused and follow the surrounding code. Add a small meaningful test for changed logic. For normal SDK changes run:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm run build
|
|
29
|
+
npm run typecheck
|
|
30
|
+
npm test
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For selection, targeting or UI changes, also build the examples and run the relevant browser tests. Use `npm run verify:package` for package changes and the compatibility/ecosystem suites for affected integrations. Report the exact commands run and any checks skipped; documentation-only edits do not require the entire browser matrix.
|
|
34
|
+
|
|
35
|
+
Run `npm run check:release` before sharing new report files. Published report excerpts replace the local project root with `[project]`; raw test outputs stay under ignored local directories. Do not include `.env`, installed dependencies, generated packages or raw recordings.
|
|
36
|
+
|
|
37
|
+
By submitting a contribution, offer your original changes under the project's [PolyForm Shield 1.0.0 license](LICENSE). Only contribute material you have the right to share, and preserve applicable third-party notices. This does not transfer your copyright to the maintainer.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Required Notice: Copyright (c) 2026 Duran Gezer
|
|
2
|
+
|
|
3
|
+
# PolyForm Shield License 1.0.0
|
|
4
|
+
|
|
5
|
+
<https://polyformproject.org/licenses/shield/1.0.0>
|
|
6
|
+
|
|
7
|
+
## Acceptance
|
|
8
|
+
|
|
9
|
+
In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
|
|
10
|
+
|
|
11
|
+
## Copyright License
|
|
12
|
+
|
|
13
|
+
The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
|
|
14
|
+
|
|
15
|
+
## Distribution License
|
|
16
|
+
|
|
17
|
+
The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
|
|
18
|
+
|
|
19
|
+
## Notices
|
|
20
|
+
|
|
21
|
+
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
|
|
22
|
+
|
|
23
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
24
|
+
|
|
25
|
+
## Changes and New Works License
|
|
26
|
+
|
|
27
|
+
The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
|
|
28
|
+
|
|
29
|
+
## Patent License
|
|
30
|
+
|
|
31
|
+
The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
|
|
32
|
+
|
|
33
|
+
## Noncompete
|
|
34
|
+
|
|
35
|
+
Any purpose is a permitted purpose, except for providing any product that competes with the software or any product the licensor or any of its affiliates provides using the software.
|
|
36
|
+
|
|
37
|
+
## Competition
|
|
38
|
+
|
|
39
|
+
Goods and services compete even when they provide functionality through different kinds of interfaces or for different technical platforms. Applications can compete with services, libraries with plugins, frameworks with development tools, and so on, even if they're written in different programming languages or for different computer architectures. Goods and services compete even when provided free of charge. If you market a product as a practical substitute for the software or another product, it definitely competes.
|
|
40
|
+
|
|
41
|
+
## New Products
|
|
42
|
+
|
|
43
|
+
If you are using the software to provide a product that does not compete, but the licensor or any of its affiliates brings your product into competition by providing a new version of the software or another product using the software, you may continue using versions of the software available under these terms beforehand to provide your competing product, but not any later versions.
|
|
44
|
+
|
|
45
|
+
## Discontinued Products
|
|
46
|
+
|
|
47
|
+
You may begin using the software to compete with a product or service that the licensor or any of its affiliates has stopped providing, unless the licensor includes a plain-text line beginning with `Licensor Line of Business:` with the software that mentions that line of business. For example:
|
|
48
|
+
|
|
49
|
+
> Licensor Line of Business: YoyodyneCMS Content Management System (http://example.com/cms)
|
|
50
|
+
|
|
51
|
+
## Sales of Business
|
|
52
|
+
|
|
53
|
+
If the licensor or any of its affiliates sells a line of business developing the software or using the software to provide a product, the buyer can also enforce [Noncompete](#noncompete) for that product.
|
|
54
|
+
|
|
55
|
+
## Fair Use
|
|
56
|
+
|
|
57
|
+
You may have "fair use" rights for the software under the law. These terms do not limit them.
|
|
58
|
+
|
|
59
|
+
## No Other Rights
|
|
60
|
+
|
|
61
|
+
These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
|
|
62
|
+
|
|
63
|
+
## Patent Defense
|
|
64
|
+
|
|
65
|
+
If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
66
|
+
|
|
67
|
+
## Violations
|
|
68
|
+
|
|
69
|
+
The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
|
|
70
|
+
|
|
71
|
+
## No Liability
|
|
72
|
+
|
|
73
|
+
***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
|
|
74
|
+
|
|
75
|
+
## Definitions
|
|
76
|
+
|
|
77
|
+
The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
|
|
78
|
+
|
|
79
|
+
A **product** can be a good or service, or a combination of them.
|
|
80
|
+
|
|
81
|
+
**You** refers to the individual or entity agreeing to these terms.
|
|
82
|
+
|
|
83
|
+
**Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all its affiliates.
|
|
84
|
+
|
|
85
|
+
**Affiliates** means the other organizations than an organization has control over, is under the control of, or is under common control with.
|
|
86
|
+
|
|
87
|
+
**Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
88
|
+
|
|
89
|
+
**Your licenses** are all the licenses granted to you for the software under these terms.
|
|
90
|
+
|
|
91
|
+
**Use** means anything you do with the software requiring one of your licenses.
|
package/README.md
CHANGED
|
@@ -1,3 +1,73 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Noktiq
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Point. Note. Paste. Visual change requests for React and Vue.**
|
|
4
|
+
|
|
5
|
+
Select an element on your development website, describe the change and copy a request into your coding agent. Noktiq includes the source file, line and column when available, plus selectors and page context. No AI account or API key is required.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install -D noktiq
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## React + Vite
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { Noktiq } from 'noktiq/react';
|
|
15
|
+
|
|
16
|
+
export default function App() {
|
|
17
|
+
return <>{/* Your application */}<Noktiq enabled={import.meta.env.DEV} /></>;
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// vite.config.ts
|
|
23
|
+
import { defineConfig } from 'vite';
|
|
24
|
+
import react from '@vitejs/plugin-react';
|
|
25
|
+
import { noktiq } from 'noktiq/vite';
|
|
26
|
+
|
|
27
|
+
export default defineConfig({ plugins: [noktiq(), react()] });
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Vue + Vite
|
|
31
|
+
|
|
32
|
+
```vue
|
|
33
|
+
<script setup>
|
|
34
|
+
import { Noktiq } from 'noktiq/vue';
|
|
35
|
+
const isDev = import.meta.env.DEV;
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<!-- Your application -->
|
|
40
|
+
<Noktiq :enabled="isDev" />
|
|
41
|
+
</template>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// vite.config.ts
|
|
46
|
+
import { defineConfig } from 'vite';
|
|
47
|
+
import vue from '@vitejs/plugin-vue';
|
|
48
|
+
import { noktiq } from 'noktiq/vite';
|
|
49
|
+
|
|
50
|
+
export default defineConfig({ plugins: [noktiq(), vue()] });
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The component is disabled by default. Keep the development guard in your application; the source plugin also runs only in development.
|
|
54
|
+
|
|
55
|
+
## Workflow
|
|
56
|
+
|
|
57
|
+
1. Click Nok to enter selection mode.
|
|
58
|
+
2. Select an element, enter your request and save the note.
|
|
59
|
+
3. Copy one note or all notes into your existing coding agent.
|
|
60
|
+
|
|
61
|
+
Drag Nok to reposition it. Notes support text, multiple elements and area selection; parent navigation; source links; live target status; rebinding; computed styles; and configurable output detail. Notes stay in your browser and are synchronized between tabs on the same origin.
|
|
62
|
+
|
|
63
|
+
## Compatibility
|
|
64
|
+
|
|
65
|
+
Tested examples cover React 18/19, Vue 3.4/3.5, Next.js 14/15/16, Nuxt 3/4, Vite 6/7/8 and Webpack 5. These tests do not guarantee every version or component combination. Closed Shadow DOM, cross-origin iframes and individual canvas/3D objects are outside the supported selection scope.
|
|
66
|
+
|
|
67
|
+
For Next.js, Nuxt, Webpack, editor configuration and all options, see the packaged [developer guide](docs/guide.tr.md). The [captured request](docs/walkthrough-request.md) shows a real output example. Demo recordings and repository-only validation reports are intentionally excluded from the npm archive.
|
|
68
|
+
|
|
69
|
+
## Privacy and license
|
|
70
|
+
|
|
71
|
+
Noktiq does not send notes to an AI service. Inspect copied context before sharing it, and mark sensitive regions with `data-noktiq-private`. Browser storage failures are reported; memory-only notes are lost on a full reload.
|
|
72
|
+
|
|
73
|
+
Source-available under [PolyForm Shield 1.0.0](LICENSE). Copyright (c) 2026 Duran Gezer. See [contributing](CONTRIBUTING.md) and [security reporting](SECURITY.md).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
Noktiq is a development tool. Its UI requires DOM access and the source integration runs in a local development server. Keep the documented development guards in place and avoid exposing your development server to untrusted networks.
|
|
4
|
+
|
|
5
|
+
## Report privately
|
|
6
|
+
|
|
7
|
+
Use the repository's **Security → Advisories → Report a vulnerability** action when available. Include affected versions, a minimal reproduction, impact and suggested mitigation. Remove real credentials and personal data.
|
|
8
|
+
|
|
9
|
+
If the private-report button is unavailable, open an issue asking the maintainer for a private reporting channel **without describing the vulnerability or posting exploit details**. Wait for a private channel before sharing the report. No public email address or response-time guarantee has been established for this preview.
|
|
10
|
+
|
|
11
|
+
Do not test against other people's projects without permission. Do not publish credentials, private source code or vulnerability details in ordinary issues or pull requests.
|
|
12
|
+
|
|
13
|
+
## Supported versions
|
|
14
|
+
|
|
15
|
+
The current development-preview version is the maintenance target. Updates are made on the current development line; historical-version backports are not promised.
|
|
16
|
+
|
|
17
|
+
## Maintainer setup
|
|
18
|
+
|
|
19
|
+
Before public release, enable GitHub private vulnerability reporting in the repository settings and verify that the report button is available. This is an account/repository setting; adding this document alone does not enable it. See [GitHub's setup instructions](https://docs.github.com/en/code-security/how-tos/report-and-fix-vulnerabilities/configure-vulnerability-reporting/configure-for-a-repository).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type ElementDetails } from './identity.js';
|
|
2
|
+
import { type Boundary } from './dom.js';
|
|
3
|
+
export interface Annotation extends ElementDetails {
|
|
4
|
+
id: string;
|
|
5
|
+
page: string;
|
|
6
|
+
selector: string;
|
|
7
|
+
tag: string;
|
|
8
|
+
text: string;
|
|
9
|
+
selectorStrategy?: 'identity' | 'structure';
|
|
10
|
+
boundaries?: Boundary[];
|
|
11
|
+
kind?: 'element' | 'text' | 'group' | 'area';
|
|
12
|
+
selectedText?: string;
|
|
13
|
+
textRange?: {
|
|
14
|
+
start: number;
|
|
15
|
+
end: number;
|
|
16
|
+
text?: string;
|
|
17
|
+
};
|
|
18
|
+
bounds?: {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
};
|
|
24
|
+
targets?: AnnotationTarget[];
|
|
25
|
+
anchor?: {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
};
|
|
29
|
+
viewport: {
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
};
|
|
33
|
+
note: string;
|
|
34
|
+
}
|
|
35
|
+
export type AnnotationTarget = Omit<Annotation, 'id' | 'note' | 'targets'>;
|
|
36
|
+
export { exportNotes } from './output.js';
|
|
37
|
+
export declare function selectorFor(element: Element): string;
|
|
38
|
+
export declare function pageKey(location: Location, useHashLocation?: boolean): string;
|
|
39
|
+
export declare function contextFor(element: Element, useHashLocation?: boolean): Omit<Annotation, 'id' | 'note'>;
|
|
40
|
+
export declare function readNotes(storage: Pick<Storage, 'getItem'>, key: string, page: string): Annotation[];
|
|
41
|
+
export declare function writeNotes(storage: Storage, key: string, notes: Annotation[]): void;
|
|
42
|
+
export declare function matchesAnnotation(element: Element, item: Annotation): boolean;
|
|
43
|
+
/** Reattach only when captured evidence identifies one element; never choose the first match. */
|
|
44
|
+
export declare function findAnnotatedElement(document: Document, item: Annotation): Element | undefined;
|
|
45
|
+
export interface LocationResult {
|
|
46
|
+
status: 'found' | 'ambiguous' | 'changed' | 'missing' | 'boundary-unavailable' | 'invalid' | 'too-many';
|
|
47
|
+
element?: Element;
|
|
48
|
+
count?: number;
|
|
49
|
+
}
|
|
50
|
+
export declare function locateAnnotation(document: Document, item: Annotation): LocationResult;
|
package/dist/dom.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type QueryRoot = Document | ShadowRoot;
|
|
2
|
+
export interface Boundary {
|
|
3
|
+
kind: 'shadow' | 'frame';
|
|
4
|
+
selector: string;
|
|
5
|
+
page?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function isElement(value: unknown): value is Element;
|
|
8
|
+
export declare function parentAcross(element: Element): Element | null;
|
|
9
|
+
export declare function closestAcross(element: Element, selector: string): Element | null;
|
|
10
|
+
export declare function routeKey(location: Location | URL, hash?: boolean): string;
|
|
11
|
+
export declare function boundariesFor(element: Element, selectorFor: (element: Element) => string): Boundary[];
|
|
12
|
+
export declare function rootFor(document: Document, path?: Boundary[]): QueryRoot | undefined;
|
|
13
|
+
export declare function hostPoint(document: Document, x: number, y: number): {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
scaleX: number;
|
|
17
|
+
scaleY: number;
|
|
18
|
+
visible: boolean;
|
|
19
|
+
};
|
|
20
|
+
export declare function hostRect(element: Element): {
|
|
21
|
+
left: number;
|
|
22
|
+
top: number;
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
right: number;
|
|
26
|
+
bottom: number;
|
|
27
|
+
visible: boolean;
|
|
28
|
+
clip: {
|
|
29
|
+
left: number;
|
|
30
|
+
top: number;
|
|
31
|
+
right: number;
|
|
32
|
+
bottom: number;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/** Observe only accessible roots. No patching of application prototypes or timers. */
|
|
36
|
+
export declare function watchContexts(host: HTMLElement, attach: (document: Document) => () => void, changed: (roots: QueryRoot[]) => void): () => void;
|
package/dist/editor.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface EditorTarget {
|
|
2
|
+
kind: 'vite' | 'next';
|
|
3
|
+
file: string;
|
|
4
|
+
base?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SourceLocation {
|
|
7
|
+
file: string;
|
|
8
|
+
line: number;
|
|
9
|
+
column: number;
|
|
10
|
+
source: string;
|
|
11
|
+
page: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function parseSource(source?: string): {
|
|
14
|
+
file: string;
|
|
15
|
+
line: number;
|
|
16
|
+
column: number;
|
|
17
|
+
} | undefined;
|
|
18
|
+
export declare function validEditor(value: unknown): value is EditorTarget;
|
|
19
|
+
export declare function editorURL(editor: EditorTarget, source: string, page: string): URL | undefined;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare const identifyingAttributes: readonly ["data-testid", "data-test", "data-test-id", "data-qa", "data-cy", "data-component", "data-row-id", "data-row-key", "data-item-id", "data-item-key", "row-id", "col-id"];
|
|
2
|
+
export declare const styleProperties: readonly ["color", "background-color", "font-family", "font-size", "font-weight", "line-height", "letter-spacing", "display", "position", "width", "height", "gap", "padding-top", "padding-right", "padding-bottom", "padding-left", "margin-top", "margin-right", "margin-bottom", "margin-left", "border-radius"];
|
|
3
|
+
import { type EditorTarget } from './editor.js';
|
|
4
|
+
export interface ElementDetails {
|
|
5
|
+
editor?: EditorTarget;
|
|
6
|
+
identifiers?: Record<string, string>;
|
|
7
|
+
ancestors?: Array<{
|
|
8
|
+
tag: string;
|
|
9
|
+
identifiers: Record<string, string>;
|
|
10
|
+
}>;
|
|
11
|
+
classes?: string[];
|
|
12
|
+
role?: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
components?: {
|
|
15
|
+
framework: 'react' | 'vue';
|
|
16
|
+
names: string[];
|
|
17
|
+
};
|
|
18
|
+
source?: string;
|
|
19
|
+
sourceScope?: string;
|
|
20
|
+
sourceKind?: 'element' | 'ancestor' | 'component-usage' | 'component';
|
|
21
|
+
sourceProvider?: 'vue-vnode';
|
|
22
|
+
componentFile?: {
|
|
23
|
+
file: string;
|
|
24
|
+
name?: string;
|
|
25
|
+
};
|
|
26
|
+
computedStyles?: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
export declare function stableId(id: string): boolean;
|
|
29
|
+
export declare function identifiersFor(element: Element): Record<string, string>;
|
|
30
|
+
export declare function attributeSelector(name: string, value: string): string;
|
|
31
|
+
/** A selector must resolve to this exact element, including with duplicate IDs. */
|
|
32
|
+
export declare function locatorFor(element: Element): {
|
|
33
|
+
selector: string;
|
|
34
|
+
selectorStrategy: 'identity' | 'structure';
|
|
35
|
+
};
|
|
36
|
+
export declare function detailsFor(element: Element, sensitive?: boolean): ElementDetails;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { NoktiqOptions } from './options.js';
|
|
2
|
+
export type { SourceLocation } from './editor.js';
|
|
3
|
+
export { exportNotes, type Annotation } from './context.js';
|
|
4
|
+
export type { NoktiqOptions } from './options.js';
|
|
5
|
+
export type { CopyFormat, OutputDetail, OutputOptions } from './output.js';
|
|
6
|
+
export type { AnnotationTarget } from './context.js';
|
|
7
|
+
/** Mount after the page is ready, only in development. Returns an idempotent cleanup. */
|
|
8
|
+
export declare function mountNoktiq(options?: NoktiqOptions): () => void;
|
package/dist/index.js
ADDED
package/dist/mascot.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Original Nok artwork; only static, trusted markup enters the SVG. */
|
|
2
|
+
export declare const nok = "\n<svg class=\"nok\" viewBox=\"0 0 100 108\" fill=\"none\" aria-hidden=\"true\">\n <defs>\n <radialGradient id=\"nok-body\" cx=\".29\" cy=\".16\" r=\".92\"><stop stop-color=\"#575754\"/><stop offset=\".47\" stop-color=\"#393A38\"/><stop offset=\"1\" stop-color=\"#242624\"/></radialGradient>\n <linearGradient id=\"nok-rim\" x1=\"19\" y1=\"10\" x2=\"83\" y2=\"92\" gradientUnits=\"userSpaceOnUse\"><stop stop-color=\"#FFFFFF\" stop-opacity=\".24\"/><stop offset=\"1\" stop-color=\"#FFFFFF\" stop-opacity=\"0\"/></linearGradient>\n <filter id=\"nok-shadow\" x=\"-30%\" y=\"-150%\" width=\"160%\" height=\"400%\"><feGaussianBlur stdDeviation=\"3.4\"/></filter>\n <filter id=\"nok-grain\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\"><feTurbulence type=\"fractalNoise\" baseFrequency=\".78\" numOctaves=\"3\" stitchTiles=\"stitch\"/><feColorMatrix type=\"saturate\" values=\"0\"/><feComposite in2=\"SourceGraphic\" operator=\"in\"/><feBlend in=\"SourceGraphic\" mode=\"soft-light\"/></filter>\n </defs>\n <ellipse class=\"nok-shadow\" cx=\"49\" cy=\"98\" rx=\"28\" ry=\"3.1\" fill=\"#252722\" opacity=\".18\" filter=\"url(#nok-shadow)\"/>\n <g class=\"nok-body\">\n <path d=\"M49 8C25 7 9 23 8 46C6 70 19 85 43 87C52 88 60 85 65 87L83 96C87 98 91 96 89 90L83 70C89 61 92 52 89 39C85 20 69 9 49 8Z\" fill=\"url(#nok-body)\"/>\n <path d=\"M49 8C25 7 9 23 8 46C6 70 19 85 43 87C52 88 60 85 65 87L83 96C87 98 91 96 89 90L83 70C89 61 92 52 89 39C85 20 69 9 49 8Z\" fill=\"url(#nok-body)\" filter=\"url(#nok-grain)\" opacity=\".16\"/>\n <path d=\"M49 8C25 7 9 23 8 46C6 70 19 85 43 87C52 88 60 85 65 87L83 96C87 98 91 96 89 90L83 70C89 61 92 52 89 39C85 20 69 9 49 8Z\" stroke=\"url(#nok-rim)\" stroke-width=\"1.1\"/>\n <g class=\"nok-gaze\">\n <g class=\"nok-blink\"><ellipse class=\"eye eye-left\" cx=\"34\" cy=\"46\" rx=\"4.5\" ry=\"9\" fill=\"#FFF8E9\"/><ellipse class=\"eye eye-right\" cx=\"57\" cy=\"43\" rx=\"4.5\" ry=\"9\" fill=\"#FFF8E9\"/></g>\n <g class=\"nok-happy\" stroke=\"#FFF8E9\" stroke-width=\"4.5\" stroke-linecap=\"round\"><path d=\"M29 47Q34 37 39 47\"/><path d=\"M52 44Q57 34 62 44\"/></g>\n </g>\n <rect class=\"nok-cheek\" x=\"69\" y=\"50\" width=\"12\" height=\"5.8\" rx=\"2.9\" transform=\"rotate(-29 69 50)\" fill=\"#FF977C\"/>\n </g>\n</svg>";
|
|
3
|
+
declare const paths: {
|
|
4
|
+
select: string;
|
|
5
|
+
notes: string;
|
|
6
|
+
copy: string;
|
|
7
|
+
edit: string;
|
|
8
|
+
trash: string;
|
|
9
|
+
close: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function icon(name: keyof typeof paths): SVGElement;
|
|
12
|
+
export {};
|
package/dist/motion.d.ts
ADDED
package/dist/next.d.ts
ADDED
package/dist/next.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/next.ts
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
function withNoktiq(config = {}) {
|
|
6
|
+
const loader = fileURLToPath(new URL("./webpack-loader.cjs", import.meta.url));
|
|
7
|
+
const [major, minor] = createRequire(resolve(process.cwd(), "package.json"))("next/package.json").version.split(".").map(Number);
|
|
8
|
+
const modern = major >= 16;
|
|
9
|
+
const pattern = modern ? "*.{js,jsx,ts,tsx}" : "*.{js,jsx,tsx}";
|
|
10
|
+
const legacy = major < 15 || major === 15 && minor < 3;
|
|
11
|
+
const experimental = config.experimental;
|
|
12
|
+
const turbo = (legacy ? experimental?.turbo : config.turbopack ?? experimental?.turbo) || {};
|
|
13
|
+
const root = turbo.root || process.cwd();
|
|
14
|
+
const { [pattern]: previous, ...otherRules } = turbo.rules || {};
|
|
15
|
+
const sourceLoader = { loader, options: { root, editor: { kind: "next", base: config.basePath || "/" }, ...!modern ? { transpileTypescript: true } : {} } };
|
|
16
|
+
const previousLoaders = Array.isArray(previous) ? previous : previous?.loaders || [];
|
|
17
|
+
const rules = modern ? {
|
|
18
|
+
[pattern]: [
|
|
19
|
+
{ condition: { all: ["development", { not: "foreign" }] }, loaders: [sourceLoader] },
|
|
20
|
+
...previous ? Array.isArray(previous) ? previous : [previous] : []
|
|
21
|
+
],
|
|
22
|
+
...otherRules
|
|
23
|
+
} : process.env.NODE_ENV === "production" ? turbo.rules : {
|
|
24
|
+
[pattern]: { ...!Array.isArray(previous) ? previous : {}, loaders: [sourceLoader, ...previousLoaders] },
|
|
25
|
+
...otherRules
|
|
26
|
+
};
|
|
27
|
+
const integration = legacy ? { experimental: { ...experimental, turbo: { ...turbo, rules } } } : { turbopack: { ...turbo, rules } };
|
|
28
|
+
return {
|
|
29
|
+
...config,
|
|
30
|
+
// Next 14/15 use rule shapes absent from the current Next type declarations.
|
|
31
|
+
...integration,
|
|
32
|
+
webpack(webpackConfig, context) {
|
|
33
|
+
const result = config.webpack?.(webpackConfig, context) || webpackConfig;
|
|
34
|
+
if (context.dev) {
|
|
35
|
+
result.module ||= {};
|
|
36
|
+
result.module.rules ||= [];
|
|
37
|
+
result.module.rules.unshift({
|
|
38
|
+
test: /\.[jt]sx?$/,
|
|
39
|
+
exclude: /node_modules/,
|
|
40
|
+
enforce: "pre",
|
|
41
|
+
use: [{ loader, options: { root, editor: { kind: "next", base: config.basePath || "/" } } }]
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
withNoktiq
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=next.js.map
|
package/dist/next.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/next.ts"],
|
|
4
|
+
"sourcesContent": ["import { fileURLToPath } from 'node:url';\r\nimport { createRequire } from 'node:module';\r\nimport { resolve } from 'node:path';\r\nimport type { NextConfig } from 'next';\r\n\r\n/** Adds development-only source locations while preserving the application's config. */\r\nexport function withNoktiq(config: NextConfig = {}): NextConfig {\r\n const loader = fileURLToPath(new URL('./webpack-loader.cjs', import.meta.url));\r\n const [major, minor] = createRequire(resolve(process.cwd(), 'package.json'))('next/package.json').version.split('.').map(Number);\r\n const modern = major >= 16;\r\n // Old Turbopack applies .ts loaders to virtual HMR modules before our loader can filter them.\r\n const pattern = modern ? '*.{js,jsx,ts,tsx}' : '*.{js,jsx,tsx}';\r\n const legacy = major < 15 || (major === 15 && minor < 3);\r\n const experimental = config.experimental as typeof config.experimental & { turbo?: NonNullable<NextConfig['turbopack']> };\r\n const turbo = (legacy ? experimental?.turbo : config.turbopack ?? experimental?.turbo) || {};\r\n const root = turbo.root || process.cwd();\r\n const { [pattern]: previous, ...otherRules } = turbo.rules || {};\r\n const sourceLoader = { loader, options: { root, editor: { kind: 'next', base: config.basePath || '/' }, ...(!modern ? { transpileTypescript: true } : {}) } };\r\n const previousLoaders = Array.isArray(previous) ? previous : previous?.loaders || [];\r\n const rules = modern ? {\r\n [pattern]: [\r\n { condition: { all: ['development', { not: 'foreign' }] }, loaders: [sourceLoader] },\r\n ...(previous ? Array.isArray(previous) ? previous : [previous] : []),\r\n ], ...otherRules,\r\n } : process.env.NODE_ENV === 'production' ? turbo.rules : {\r\n [pattern]: { ...(!Array.isArray(previous) ? previous : {}), loaders: [sourceLoader, ...previousLoaders] }, ...otherRules,\r\n };\r\n const integration = legacy\r\n ? { experimental: { ...experimental, turbo: { ...turbo, rules } } }\r\n : { turbopack: { ...turbo, rules } };\r\n return {\r\n ...config,\r\n // Next 14/15 use rule shapes absent from the current Next type declarations.\r\n ...(integration as NextConfig),\r\n webpack(webpackConfig, context) {\r\n const result = config.webpack?.(webpackConfig, context) || webpackConfig;\r\n if (context.dev) { result.module ||= {}; result.module.rules ||= []; result.module.rules.unshift({\r\n test: /\\.[jt]sx?$/, exclude: /node_modules/, enforce: 'pre',\r\n use: [{ loader, options: { root, editor: { kind: 'next', base: config.basePath || '/' } } }],\r\n }); }\r\n return result;\r\n },\r\n };\r\n}\r\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AAIjB,SAAS,WAAW,SAAqB,CAAC,GAAe;AAC9D,QAAM,SAAS,cAAc,IAAI,IAAI,wBAAwB,YAAY,GAAG,CAAC;AAC7E,QAAM,CAAC,OAAO,KAAK,IAAI,cAAc,QAAQ,QAAQ,IAAI,GAAG,cAAc,CAAC,EAAE,mBAAmB,EAAE,QAAQ,MAAM,GAAG,EAAE,IAAI,MAAM;AAC/H,QAAM,SAAS,SAAS;AAExB,QAAM,UAAU,SAAS,sBAAsB;AAC/C,QAAM,SAAS,QAAQ,MAAO,UAAU,MAAM,QAAQ;AACtD,QAAM,eAAe,OAAO;AAC5B,QAAM,SAAS,SAAS,cAAc,QAAQ,OAAO,aAAa,cAAc,UAAU,CAAC;AAC3F,QAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI;AACvC,QAAM,EAAE,CAAC,OAAO,GAAG,UAAU,GAAG,WAAW,IAAI,MAAM,SAAS,CAAC;AAC/D,QAAM,eAAe,EAAE,QAAQ,SAAS,EAAE,MAAM,QAAQ,EAAE,MAAM,QAAQ,MAAM,OAAO,YAAY,IAAI,GAAG,GAAI,CAAC,SAAS,EAAE,qBAAqB,KAAK,IAAI,CAAC,EAAG,EAAE;AAC5J,QAAM,kBAAkB,MAAM,QAAQ,QAAQ,IAAI,WAAW,UAAU,WAAW,CAAC;AACnF,QAAM,QAAQ,SAAS;AAAA,IACrB,CAAC,OAAO,GAAG;AAAA,MACT,EAAE,WAAW,EAAE,KAAK,CAAC,eAAe,EAAE,KAAK,UAAU,CAAC,EAAE,GAAG,SAAS,CAAC,YAAY,EAAE;AAAA,MACnF,GAAI,WAAW,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ,IAAI,CAAC;AAAA,IACpE;AAAA,IAAG,GAAG;AAAA,EACR,IAAI,QAAQ,IAAI,aAAa,eAAe,MAAM,QAAQ;AAAA,IACxD,CAAC,OAAO,GAAG,EAAE,GAAI,CAAC,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,GAAI,SAAS,CAAC,cAAc,GAAG,eAAe,EAAE;AAAA,IAAG,GAAG;AAAA,EAChH;AACA,QAAM,cAAc,SAChB,EAAE,cAAc,EAAE,GAAG,cAAc,OAAO,EAAE,GAAG,OAAO,MAAM,EAAE,EAAE,IAChE,EAAE,WAAW,EAAE,GAAG,OAAO,MAAM,EAAE;AACrC,SAAO;AAAA,IACL,GAAG;AAAA;AAAA,IAEH,GAAI;AAAA,IACJ,QAAQ,eAAe,SAAS;AAC9B,YAAM,SAAS,OAAO,UAAU,eAAe,OAAO,KAAK;AAC3D,UAAI,QAAQ,KAAK;AAAE,eAAO,WAAW,CAAC;AAAG,eAAO,OAAO,UAAU,CAAC;AAAG,eAAO,OAAO,MAAM,QAAQ;AAAA,UAC/F,MAAM;AAAA,UAAc,SAAS;AAAA,UAAgB,SAAS;AAAA,UACtD,KAAK,CAAC,EAAE,QAAQ,SAAS,EAAE,MAAM,QAAQ,EAAE,MAAM,QAAQ,MAAM,OAAO,YAAY,IAAI,EAAE,EAAE,CAAC;AAAA,QAC7F,CAAC;AAAA,MAAG;AACJ,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface NoktiqOptions {
|
|
2
|
+
portalContainer?: HTMLElement | ShadowRoot | null | (() => HTMLElement | ShadowRoot | null);
|
|
3
|
+
useHashLocation?: boolean;
|
|
4
|
+
enableKeyboardShortcuts?: boolean;
|
|
5
|
+
outputDetail?: import('./output.js').OutputDetail;
|
|
6
|
+
copyFormat?: import('./output.js').CopyFormat;
|
|
7
|
+
openInEditor?: (location: import('./editor.js').SourceLocation) => void | Promise<void>;
|
|
8
|
+
}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Annotation } from './context.js';
|
|
2
|
+
export type OutputDetail = 'compact' | 'standard' | 'detailed';
|
|
3
|
+
export type CopyFormat = 'markdown' | 'source' | 'classes';
|
|
4
|
+
export interface OutputOptions {
|
|
5
|
+
detail?: OutputDetail;
|
|
6
|
+
format?: CopyFormat;
|
|
7
|
+
}
|
|
8
|
+
export declare function exportNotes(notes: Annotation[], options?: OutputOptions): string;
|
package/dist/react.d.ts
ADDED
package/dist/react.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
mountNoktiq
|
|
4
|
+
} from "./shared-chunk.js";
|
|
5
|
+
|
|
6
|
+
// src/react.ts
|
|
7
|
+
import { useEffect, useRef } from "react";
|
|
8
|
+
function Noktiq({ enabled = false, ...options }) {
|
|
9
|
+
const current = useRef(options);
|
|
10
|
+
current.current = options;
|
|
11
|
+
useEffect(() => enabled ? mountNoktiq({ ...options, portalContainer: () => {
|
|
12
|
+
const target = current.current.portalContainer;
|
|
13
|
+
return typeof target === "function" ? target() : target ?? null;
|
|
14
|
+
}, openInEditor: options.openInEditor ? (location) => current.current.openInEditor?.(location) : void 0 }) : void 0, [enabled, options.useHashLocation, options.enableKeyboardShortcuts, options.outputDetail, options.copyFormat, !!options.openInEditor]);
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
Noktiq
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/react.ts"],
|
|
4
|
+
"sourcesContent": ["'use client';\nimport { useEffect, useRef } from 'react';\nimport { mountNoktiq } from './index.js';\nimport type { NoktiqOptions } from './options.js';\n\nexport function Noktiq({ enabled = false, ...options }: NoktiqOptions & { enabled?: boolean }) {\n const current = useRef(options); current.current = options;\n useEffect(() => enabled ? mountNoktiq({ ...options, portalContainer: () => {\n const target = current.current.portalContainer;\n return typeof target === 'function' ? target() : target ?? null;\n }, openInEditor: options.openInEditor ? location => current.current.openInEditor?.(location) : undefined }) : undefined, [enabled, options.useHashLocation, options.enableKeyboardShortcuts, options.outputDetail, options.copyFormat, !!options.openInEditor]);\n return null;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;AACA,SAAS,WAAW,cAAc;AAI3B,SAAS,OAAO,EAAE,UAAU,OAAO,GAAG,QAAQ,GAA0C;AAC7F,QAAM,UAAU,OAAO,OAAO;AAAG,UAAQ,UAAU;AACnD,YAAU,MAAM,UAAU,YAAY,EAAE,GAAG,SAAS,iBAAiB,MAAM;AACzE,UAAM,SAAS,QAAQ,QAAQ;AAC/B,WAAO,OAAO,WAAW,aAAa,OAAO,IAAI,UAAU;AAAA,EAC7D,GAAG,cAAc,QAAQ,eAAe,cAAY,QAAQ,QAAQ,eAAe,QAAQ,IAAI,OAAU,CAAC,IAAI,QAAW,CAAC,SAAS,QAAQ,iBAAiB,QAAQ,yBAAyB,QAAQ,cAAc,QAAQ,YAAY,CAAC,CAAC,QAAQ,YAAY,CAAC;AAC9P,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare function selectedText(document: Document): {
|
|
2
|
+
element: Element;
|
|
3
|
+
range: Range;
|
|
4
|
+
selectedText: string;
|
|
5
|
+
textRange: {
|
|
6
|
+
text?: string | undefined;
|
|
7
|
+
start: number;
|
|
8
|
+
end: number;
|
|
9
|
+
};
|
|
10
|
+
} | undefined;
|
|
11
|
+
export declare function textRangeFor(element: Element, offsets: {
|
|
12
|
+
start: number;
|
|
13
|
+
end: number;
|
|
14
|
+
text?: string;
|
|
15
|
+
}, text: string): Range | undefined;
|
|
16
|
+
export declare function elementsInArea(roots: Array<Document | ShadowRoot>, area: {
|
|
17
|
+
left: number;
|
|
18
|
+
top: number;
|
|
19
|
+
right: number;
|
|
20
|
+
bottom: number;
|
|
21
|
+
}, host: Element): Element[];
|