pax_global_header 0000666 0000000 0000000 00000000064 15202310201 0014474 g ustar 00root root 0000000 0000000 52 comment=fce6ed7a6d5f2c7333d9c26fb09f5bb9e929a737
preact-10.29.2/ 0000775 0000000 0000000 00000000000 15202310201 0013125 5 ustar 00root root 0000000 0000000 preact-10.29.2/.editorconfig 0000664 0000000 0000000 00000000346 15202310201 0015605 0 ustar 00root root 0000000 0000000 root = true
[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.json,.*rc,*.yml}]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
preact-10.29.2/.eslintignore 0000664 0000000 0000000 00000000020 15202310201 0015620 0 ustar 00root root 0000000 0000000 dist
benchmarks
preact-10.29.2/.github/ 0000775 0000000 0000000 00000000000 15202310201 0014465 5 ustar 00root root 0000000 0000000 preact-10.29.2/.github/CODEOWNERS 0000664 0000000 0000000 00000000112 15202310201 0016052 0 ustar 00root root 0000000 0000000 # Request review for GitHub configuration changes.
.github/ @JoviDeCroock
preact-10.29.2/.github/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000006217 15202310201 0017272 0 ustar 00root root 0000000 0000000 # Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@preactjs.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
preact-10.29.2/.github/FUNDING.yml 0000664 0000000 0000000 00000000053 15202310201 0016300 0 ustar 00root root 0000000 0000000 github: [preactjs]
open_collective: preact
preact-10.29.2/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 15202310201 0016650 5 ustar 00root root 0000000 0000000 preact-10.29.2/.github/ISSUE_TEMPLATE/bug_report.md 0000664 0000000 0000000 00000001245 15202310201 0021344 0 ustar 00root root 0000000 0000000 ---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
- [ ] Check if updating to the latest Preact version resolves the issue
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
If possible, please provide a link to a StackBlitz/CodeSandbox/Codepen project or a GitHub repository that demonstrates the issue. You can use the following template on StackBlitz to get started: https://stackblitz.com/edit/create-preact-starter
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. See error
**Expected behavior**
What should have happened when following the steps above?
preact-10.29.2/.github/ISSUE_TEMPLATE/feature_request.md 0000664 0000000 0000000 00000000525 15202310201 0022377 0 ustar 00root root 0000000 0000000 ---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature request
assignees: ''
---
**Describe the feature you'd love to see**
A clear and concise description of what you'd love to see added to Preact.
**Additional context (optional)**
Add any other context or screenshots about the feature request here.
preact-10.29.2/.github/workflows/ 0000775 0000000 0000000 00000000000 15202310201 0016522 5 ustar 00root root 0000000 0000000 preact-10.29.2/.github/workflows/benchmarks.yml 0000664 0000000 0000000 00000004142 15202310201 0021363 0 ustar 00root root 0000000 0000000 name: Benchmarks
on:
workflow_dispatch:
workflow_call:
jobs:
prepare:
name: Prepare environment
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Download locally built preact package
uses: actions/download-artifact@v4
with:
name: npm-package
- run: mv preact.tgz preact-local.tgz
- name: Download base package
uses: andrewiggins/download-base-artifact@v3
with:
artifact: npm-package
workflow: ci.yml
required: false
- run: mv preact.tgz preact-main.tgz
- name: Upload locally build & base preact package
uses: actions/upload-artifact@v4
with:
name: bench-environment
path: |
preact-local.tgz
preact-main.tgz
bench_todo:
name: Bench todo
uses: ./.github/workflows/run-bench.yml
needs: prepare
with:
benchmark: todo/todo
timeout: 10
bench_text_update:
name: Bench text-update
uses: ./.github/workflows/run-bench.yml
needs: prepare
with:
benchmark: text-update/text-update
timeout: 10
bench_many_updates:
name: Bench many-updates
uses: ./.github/workflows/run-bench.yml
needs: prepare
with:
benchmark: many-updates/many-updates
timeout: 10
bench_replace1k:
name: Bench replace1k
uses: ./.github/workflows/run-bench.yml
needs: prepare
with:
benchmark: table-app/replace1k
bench_update10th1k:
name: Bench 03_update10th1k_x16
uses: ./.github/workflows/run-bench.yml
needs: prepare
with:
benchmark: table-app/update10th1k
bench_create10k:
name: Bench create10k
uses: ./.github/workflows/run-bench.yml
needs: prepare
with:
benchmark: table-app/create10k
bench_hydrate1k:
name: Bench hydrate1k
uses: ./.github/workflows/run-bench.yml
needs: prepare
with:
benchmark: table-app/hydrate1k
bench_filter_list:
name: Bench filter-list
uses: ./.github/workflows/run-bench.yml
needs: prepare
with:
benchmark: filter-list/filter-list
timeout: 10
preact-10.29.2/.github/workflows/build-test.yml 0000664 0000000 0000000 00000003171 15202310201 0021323 0 ustar 00root root 0000000 0000000 name: Build & Test
on:
workflow_dispatch:
workflow_call:
inputs:
ref:
description: 'Branch or tag ref to check out'
type: string
required: false
default: ''
artifact_name:
description: 'Name of the artifact to upload'
type: string
required: false
default: 'npm-package'
permissions:
contents: read
jobs:
build_test:
name: Build & Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.ref || '' }}
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: 'package.json'
- run: npm ci
- name: test
env:
CI: true
COVERAGE: true
FLAKEY: false
# Not using `npm test` since it rebuilds source which npm ci has already done
run: npm run lint && npm run test:unit
- name: Coveralls GitHub Action
uses: coverallsapp/github-action@643bc377ffa44ace6394b2b5d0d3950076de9f63 # v2.3.0
timeout-minutes: 2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fail-on-error: false
- name: Package
# Use --ignore-scripts here to avoid re-building again before pack
run: |
npm pack --ignore-scripts
mv preact-*.tgz preact.tgz
- name: Upload npm package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ inputs.artifact_name || 'npm-package' }}
path: preact.tgz
preact-10.29.2/.github/workflows/ci.yml 0000664 0000000 0000000 00000002043 15202310201 0017637 0 ustar 00root root 0000000 0000000 name: CI
on:
workflow_dispatch:
pull_request:
branches:
- '**'
push:
branches:
- main
- v10.x
jobs:
filter_jobs:
name: Filter jobs
runs-on: ubuntu-latest
outputs:
jsChanged: ${{ steps.filter.outputs.jsChanged }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
# Should be kept in sync with the filter in the PR Reporter workflow
predicate-quantifier: 'every'
filters: |
jsChanged:
- '**/src/**/*.js'
- '!devtools/src/devtools.js'
compressed_size:
name: Compressed Size
needs: filter_jobs
if: ${{ needs.filter_jobs.outputs.jsChanged == 'true' }}
uses: ./.github/workflows/size.yml
build_test:
name: Build & Test
needs: filter_jobs
uses: ./.github/workflows/build-test.yml
benchmarks:
name: Benchmarks
needs: build_test
if: ${{ needs.filter_jobs.outputs.jsChanged == 'true' }}
uses: ./.github/workflows/benchmarks.yml
preact-10.29.2/.github/workflows/pr-reporter.yml 0000664 0000000 0000000 00000005506 15202310201 0021534 0 ustar 00root root 0000000 0000000 name: Report Results to PR
on:
# The pull_request event can't write comments for PRs from forks so using this
# workflow_run workflow as a workaround
workflow_run:
workflows: ['CI']
types:
- completed
- requested
jobs:
filter_jobs:
name: Filter jobs
runs-on: ubuntu-latest
if: |
github.event.workflow_run.event == 'pull_request'
outputs:
jsChanged: ${{ steps.filter.outputs.jsChanged }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
# As this Workflow is triggered by a `workflow_run` event, the filter action
# can't automatically assume we're working with PR data. As such, we need to
# wire it up manually with a base (merge target) and ref (source branch).
base: ${{ github.event.workflow_run.pull_requests[0].base.sha }}
ref: ${{ github.event.workflow_run.pull_requests[0].head.sha }}
# Should be kept in sync with the filter in the CI workflow
predicate-quantifier: 'every'
filters: |
jsChanged:
- '**/src/**/*.js'
- '!devtools/src/devtools.js'
report_running:
name: Report benchmarks are in-progress
needs: filter_jobs
runs-on: ubuntu-latest
# Only add the "benchmarks are running" text when a workflow_run is
# requested (a.k.a starting)
if: |
needs.filter_jobs.outputs.jsChanged == 'true' &&
github.event.action == 'requested'
steps:
- name: Report Tachometer Running
uses: andrewiggins/tachometer-reporter-action@v2
with:
# Set initialize to true so this action just creates the comment or
# adds the "benchmarks are running" text
initialize: true
report_results:
name: Report benchmark results
needs: filter_jobs
runs-on: ubuntu-latest
# Only run this job if the event action was "completed" and the triggering
# workflow_run was successful
if: |
needs.filter_jobs.outputs.jsChanged == 'true' &&
github.event.action == 'completed' &&
github.event.workflow_run.conclusion == 'success'
steps:
# Download the artifact from the triggering workflow that contains the
# Tachometer results to report
- uses: dawidd6/action-download-artifact@v2
with:
workflow: ${{ github.event.workflow.id }}
run_id: ${{ github.event.workflow_run.id }}
name_is_regexp: true
name: results-*
path: results
# Create/update the comment with the latest results
- name: Report Tachometer Results
uses: andrewiggins/tachometer-reporter-action@v2
with:
path: results/**/*.json
base-bench-name: preact-main
pr-bench-name: preact-local
summarize: 'duration, usedJSHeapSize'
preact-10.29.2/.github/workflows/release.yml 0000664 0000000 0000000 00000007440 15202310201 0020672 0 ustar 00root root 0000000 0000000 name: Release
on:
push:
tags:
- '10.*'
permissions:
contents: read
jobs:
build:
if: github.event.deleted == false
permissions:
contents: read
uses: ./.github/workflows/build-test.yml
release:
runs-on: ubuntu-latest
needs: build
permissions:
contents: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: npm-package
- name: Create draft release
id: create-release
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
with:
script: |
const script = require('./scripts/release/create-gh-release.js')
return script({ github, context })
- name: Upload release artifact
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
env:
RELEASE_DATA: ${{ steps.create-release.outputs.result }}
with:
script: |
const script = require('./scripts/release/upload-gh-asset.js')
const release = JSON.parse(process.env.RELEASE_DATA)
return script({ require, github, context, glob, release })
publish:
needs: [build, release]
runs-on: ubuntu-latest
environment:
name: npm
url: https://www.npmjs.com/package/preact
permissions:
contents: read
id-token: write
steps:
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: npm-package
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- name: Update npm
run: npm install -g npm@11.11.1
- name: Validate package
run: |
set -euo pipefail
TAG="${GITHUB_REF_NAME}"
mkdir -p package-metadata
tar -xOf preact.tgz package/package.json > package-metadata/package.json
PACKAGE_NAME="$(node -p "require('./package-metadata/package.json').name")"
PACKAGE_VERSION="$(node -p "require('./package-metadata/package.json').version")"
if [[ "$PACKAGE_NAME" != "preact" ]]; then
echo "::error::Expected package name 'preact', got '$PACKAGE_NAME'"
exit 1
fi
if [[ "$PACKAGE_VERSION" != "$TAG" ]]; then
echo "::error::Tag '$TAG' does not match package version '$PACKAGE_VERSION'"
exit 1
fi
# Determine the npm dist-tag from the git tag:
# - Stable versions publish with --tag latest
# - Prerelease versions must use an approved prerelease identifier as the
# dist-tag (10.29.0-rc.1 -> rc, 10.29.0-beta.1 -> beta)
- name: Determine dist-tag
id: dist-tag
run: |
set -euo pipefail
TAG="${GITHUB_REF_NAME}"
if [[ "$TAG" =~ ^10\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
echo "tag=latest" >> "$GITHUB_OUTPUT"
elif [[ "$TAG" =~ ^10\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)-([0-9A-Za-z-]+)(\.[0-9A-Za-z-]+)*$ ]]; then
DIST_TAG="${BASH_REMATCH[3]}"
case "$DIST_TAG" in
alpha|beta|rc|next)
echo "tag=$DIST_TAG" >> "$GITHUB_OUTPUT"
;;
*)
echo "::error::Refusing to publish prerelease '$TAG' with unapproved npm dist-tag '$DIST_TAG'"
exit 1
;;
esac
else
echo "::error::Unexpected release tag '$TAG'"
exit 1
fi
- name: Publish to npm
run: npm publish preact.tgz --provenance --access public --tag "${{ steps.dist-tag.outputs.tag }}"
preact-10.29.2/.github/workflows/run-bench.yml 0000664 0000000 0000000 00000010671 15202310201 0021133 0 ustar 00root root 0000000 0000000 name: Benchmark Worker
# Expectations:
#
# This workflow expects calling workflows to have uploaded an artifact named
# "bench-environment" that contains any built artifacts required to run the
# benchmark. This typically is the dist/ folder that running `npm run build`
# produces and/or a tarball of a previous build to bench the local build against
on:
workflow_call:
inputs:
benchmark:
description: 'The name of the benchmark to run. Should be name of an HTML file without the .html extension'
type: string
required: true
trace:
description: 'Whether to capture browser traces for this benchmark run'
type: boolean
required: false
default: false
timeout:
description: 'How many minutes to give the benchmark to run before timing out and failing'
type: number
required: false
default: 20
jobs:
run_bench:
name: Bench ${{ inputs.benchmark }}
runs-on: ubuntu-latest
timeout-minutes: ${{ inputs.timeout }}
steps:
- uses: actions/checkout@v4
with:
submodules: 'recursive'
- uses: actions/setup-node@v4
with:
node-version-file: 'package.json'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
# Setup pnpm
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 8
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
# Install benchmark dependencies
- uses: actions/download-artifact@v4
with:
name: bench-environment
- name: Move tarballs from env to correct location
run: |
ls -al
mv preact-local.tgz benchmarks/dependencies/preact/local-pinned/preact-local-pinned.tgz
ls -al benchmarks/dependencies/preact/local-pinned
mv preact-main.tgz benchmarks/dependencies/preact/main/preact-main.tgz
ls -al benchmarks/dependencies/preact/main
- name: Install deps
working-directory: benchmarks
# Set the CHROMEDRIVER_FILEPATH so the chromedriver npm package uses the
# correct binary when its installed
run: |
export CHROMEDRIVER_FILEPATH=$(which chromedriver)
pnpm install
# Install local dependencies with --no-frozen-lockfile to ensure local tarballs
# are installed regardless of if they match the integrity hash stored in the lockfile
pnpm install --no-frozen-lockfile --filter ./dependencies
# Run benchmark
- name: Run benchmark
working-directory: benchmarks
run: |
export CHROMEDRIVER_FILEPATH=$(which chromedriver)
pnpm run bench apps/${{ inputs.benchmark }}.html -d preact@local-pinned -d preact@main --trace=${{ inputs.trace }}
# Prepare output
- name: Anaylze logs if present
working-directory: benchmarks
run: '[ -d out/logs ] && pnpm run analyze ${{ inputs.benchmark }} || echo "No logs to analyze"'
- name: Tar logs if present
working-directory: benchmarks
run: |
if [ -d out/logs ]; then
LOGS_FILE=out/${{ inputs.benchmark }}_logs.tgz
mkdir -p $(dirname $LOGS_FILE)
tar -zcvf $LOGS_FILE out/logs
else
echo "No logs found"
fi
# Upload results and logs
- name: Calculate log artifact name
id: log-artifact-name
run: |
NAME=$(echo "${{ inputs.benchmark }}" | sed -r 's/[\/]+/_/g')
echo "clean_name=$NAME" >> $GITHUB_OUTPUT
echo "artifact_name=logs_$NAME" >> $GITHUB_OUTPUT
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: results-${{ steps.log-artifact-name.outputs.clean_name }}
path: benchmarks/out/results/${{ inputs.benchmark }}.json
- name: Upload logs
uses: actions/upload-artifact@v4
with:
name: ${{ steps.log-artifact-name.outputs.artifact_name }}
path: benchmarks/out/${{ inputs.benchmark }}_logs.tgz
if-no-files-found: ignore
preact-10.29.2/.github/workflows/single-bench.yml 0000664 0000000 0000000 00000005006 15202310201 0021604 0 ustar 00root root 0000000 0000000 name: Benchmark Debug
on:
workflow_dispatch:
inputs:
benchmark:
description: 'Which benchmark to run'
type: choice
options:
- table-app/replace1k
- table-app/update10th1k
- table-app/create10k
- table-app/hydrate1k
- filter_list/filter-list
- many-updates/many-updates
- text-update/text-update
- todo/todo
required: true
base:
description: 'The branch name, tag, or commit sha of the version of preact to benchmark against.'
type: string
default: main
required: false
trace:
description: 'Whether to capture browser traces for this benchmark run'
type: boolean
default: true
required: false
# A bug in GitHub actions prevents us from passing numbers (as either
# number or string type) to called workflows. So disabling this for now.
# See: https://github.com/orgs/community/discussions/67182
#
# timeout:
# description: 'How many minutes to give the benchmark to run before timing out and failing'
# type: number
# default: 20
# required: false
jobs:
build_local:
name: Build local package
uses: ./.github/workflows/ci.yml
build_base:
name: Build base package
uses: ./.github/workflows/ci.yml
with:
ref: ${{ inputs.base }}
artifact_name: base-npm-package
prepare:
name: Prepare environment
runs-on: ubuntu-latest
needs:
- build_local
- build_base
timeout-minutes: 5
steps:
- name: Download locally built preact package
uses: actions/download-artifact@v4
with:
name: npm-package
- run: mv preact.tgz preact-local.tgz
- name: Clear working directory
run: |
ls -al
rm -rf *
echo "===================="
ls -al
- name: Download base package
uses: actions/download-artifact@v4
with:
name: base-npm-package
- run: mv preact.tgz preact-main.tgz
- name: Upload locally built & base preact package
uses: actions/upload-artifact@v4
with:
name: bench-environment
path: |
preact-local.tgz
preact-main.tgz
benchmark:
name: Bench ${{ inputs.benchmark }}
uses: ./.github/workflows/run-bench.yml
needs: prepare
with:
benchmark: ${{ inputs.benchmark }}
trace: ${{ inputs.trace }}
# timeout: ${{ inputs.timeout }}
preact-10.29.2/.github/workflows/size.yml 0000664 0000000 0000000 00000001117 15202310201 0020217 0 ustar 00root root 0000000 0000000 name: Compressed Size
on:
workflow_call:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: 'package.json'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- uses: preactjs/compressed-size-action@v2
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
# Our `prepare` script already builds the app post-install,
# building it again would be redundant
build-script: 'npm run --if-present noop'
preact-10.29.2/.gitignore 0000664 0000000 0000000 00000000237 15202310201 0015117 0 ustar 00root root 0000000 0000000 .DS_Store
node_modules
npm-debug.log
dist
*/package-lock.json
yarn.lock
.vscode
.idea
test/ts/**/*.js
coverage
*.sw[op]
*.log
package/
preact-*.tgz
preact.tgz
preact-10.29.2/.gitmodules 0000664 0000000 0000000 00000000132 15202310201 0015276 0 ustar 00root root 0000000 0000000 [submodule "benchmarks"]
path = benchmarks
url = https://github.com/preactjs/benchmarks
preact-10.29.2/.husky/ 0000775 0000000 0000000 00000000000 15202310201 0014346 5 ustar 00root root 0000000 0000000 preact-10.29.2/.husky/pre-commit 0000664 0000000 0000000 00000000020 15202310201 0016335 0 ustar 00root root 0000000 0000000 npx nano-staged
preact-10.29.2/.oxfmtrc.json 0000664 0000000 0000000 00000001725 15202310201 0015565 0 ustar 00root root 0000000 0000000 {
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"endOfLine": "lf",
"insertFinalNewline": true,
"useTabs": true,
"tabWidth": 2,
"printWidth": 80,
"singleQuote": true,
"jsxSingleQuote": false,
"quoteProps": "as-needed",
"trailingComma": "none",
"semi": true,
"arrowParens": "avoid",
"bracketSameLine": false,
"bracketSpacing": true,
"singleAttributePerLine": false,
"experimentalSortPackageJson": false,
"ignorePatterns": [
"benchmarks/**",
"**/.DS_Store",
"**/node_modules",
"**/npm-debug.log",
"**/dist",
"*/package-lock.json",
"**/yarn.lock",
"**/.vscode",
"**/.idea",
"test/ts/**/*.js",
"**/coverage",
"**/*.sw[op]",
"**/*.log",
"**/package/",
"**/preact-*.tgz",
"**/preact.tgz",
"**/package-lock.json"
],
"overrides": [
{
"files": ["*.json", ".*rc", "*.yml"],
"options": {
"useTabs": false,
"tabWidth": 2
}
}
]
}
preact-10.29.2/.prettierignore 0000664 0000000 0000000 00000000262 15202310201 0016170 0 ustar 00root root 0000000 0000000 .DS_Store
node_modules
npm-debug.log
dist
*/package-lock.json
yarn.lock
.vscode
.idea
test/ts/**/*.js
coverage
*.sw[op]
*.log
package/
preact-*.tgz
preact.tgz
package-lock.json
preact-10.29.2/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000006217 15202310201 0015732 0 ustar 00root root 0000000 0000000 # Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@preactjs.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
preact-10.29.2/CONTRIBUTING.md 0000664 0000000 0000000 00000036545 15202310201 0015373 0 ustar 00root root 0000000 0000000 # Contributing
This document is intended for developers interest in making contributions to Preact and document our internal processes like releasing a new version.
## Getting Started
This steps will help you to set up your development environment. That includes all dependencies we use to build Preact and developer tooling like git commit hooks.
1. Clone the git repository: `git clone git@github.com:preactjs/preact.git`
2. Go into the cloned folder: `cd preact/`
3. Install all dependencies: `npm install`
## The Repo Structure
This repository contains Preact itself, as well as several addons like the debugging package for example. This is reflected in the directory structure of this repository. Each package has a `src/` folder where the source code can be found, a `test` folder for all sorts of tests that check if the code in `src/` is correct, and a `dist/` folder where you can find the bundled artifacts. Note that the `dist/` folder may not be present initially. It will be created as soon as you run any of the build scripts inside `package.json`. More on that later ;)
A quick overview of our repository:
```bash
# The repo root (folder where you cloned the repo into)
/
src/ # Source code of our core
test/ # Unit tests for core
dist/ # Build artifacts for publishing on npm (may not be present)
# Sub-package, can be imported via `preact/compat` by users.
# Compat stands for react-compatibility layer which tries to mirror the
# react API as close as possible (mostly legacy APIs)
compat/
src/ # Source code of the compat addon
test/ # Tests related to the compat addon
dist/ # Build artifacts for publishing on npm (may not be present)
# Sub-package, can be imported via `preact/hooks` by users.
# The hooks API is an effect based API to deal with component lifcycles.
# It's similar to hooks in React
hooks/
src/ # Source code of the hooks addon
test/ # Tests related to the hooks addon
dist/ # Build artifacts for publishing on npm (may not be present)
# Sub-package, can be imported via `preact/debug` by users.
# Includes debugging warnings and error messages for common mistakes found
# in Preact application. Also hosts the devtools bridge
debug/
src/ # Source code of the debug addon
test/ # Tests related to the debug addon
dist/ # Build artifacts for publishing on npm (may not be present)
# Sub-package, can be imported via `preact/test-utils` by users.
# Provides helpers to make testing Preact applications easier
test-utils/
src/ # Source code of the test-utils addon
test/ # Tests related to the test-utils addon
dist/ # Build artifacts for publishing on npm (may not be present)
# A demo application that we use to debug tricky errors and play with new
# features.
demo/
# Contains build scripts and dependencies for development
package.json
```
_Note: The code for rendering Preact on the server lives in another repo and is a completely separate npm package. It can be found here: [https://github.com/preactjs/preact-render-to-string](https://github.com/preactjs/preact-render-to-string)_
### What does `mangle.json` do?
It's a special file that can be used to specify how `terser` (previously known as `uglify`) will minify variable names. Because each sub-package has it's own distribution files we need to ensure that the variable names stay consistent across bundles.
## What does `options.js` do?
Unique to Preact we do support several ways to hook into our renderer. All our addons use that to inject code at different stages of a render process. They are documented in our typings in `internal.d.ts`. The core itself doesn't make use of them, which is why the file only contains an empty `object`.
## Important Branches
We merge every PR into the `main` branch which is the one that we'll use to publish code to npm. For the previous Preact release line we have a branch called `8` which is in maintenance mode. As a new contributor you won't have to deal with that ;)
## Creating your first Pull-Request
We try to make it as easy as possible to contribute to Preact and make heavy use of GitHub's "Draft PR" feature which tags Pull-Requests (short = PR) as work in progress. PRs tend to be published as soon as there is an idea that the developer deems worthwhile to include into Preact and has written some rough code. The PR doesn't have to be perfect or anything really ;)
Once a PR or a Draft PR has been created our community typically joins the discussion about the proposed change. Sometimes that includes ideas for test cases or even different ways to go about implementing a feature. Often this also includes ideas on how to make the code smaller. We usually refer to the latter as "code-golfing" or just "golfing".
When everything is good to go someone will approve the PR and the changes will be merged into the `main` branch and we usually cut a release a few days/ a week later.
_The big takeaway for you here is, that we will guide you along the way. We're here to help to make a PR ready for approval!_
The short summary is:
1. Make changes and submit a PR
2. Modify change according to feedback (if there is any)
3. PR will be merged into `main`
4. A new release will be cut (every 2-3 weeks).
## Commonly used scripts for contributions
Scripts can be executed via `npm run [script]` or `yarn [script]` respectively.
- `build` - compiles all packages ready for publishing to npm
- `build:core` - builds just Preact itself
- `build:debug` - builds the debug addon only
- `build:hooks` - builds the hook addon only
- `build:test-utils` - builds the test-utils addon only
- `test:ts` - Run all tests for TypeScript definitions
- `test:karma` - Run all unit/integration tests.
- `test:karma:watch` - Same as above, but it will automatically re-run the test suite if a code change was detected.
But to be fair, the only ones we use ourselves are `build` and `test:karma:watch`. The other ones are mainly used on our CI pipeline and we rarely use them.
_Note: Both `test:karma` and `test:karma:watch` listen to the environment variable `COVERAGE=true`. Disabling code coverage can significantly speed up the time it takes to complete the test suite._
_Note2: The test suite is based on `karma` and `mocha`. Individual tests can be executed by appending `.only`:_
```jsx
it.only('should test something', () => {
expect(1).to.equal(1);
});
```
## Common terminology and variable names
- `vnode` -> shorthand for `virtual-node` which is an object that specifies how a Component or DOM-node looks like
- `commit` -> A commit is the moment in time when you flush all changes to the DOM
- `c` -> The variable `c` always refers to a `component` instance throughout our code base.
- `diff/diffing` -> Diffing describes the process of comparing two "things". In our case we compare the previous `vnode` tree with the new one and apply the delta to the DOM.
- `root` -> The topmost node of a `vnode` tree
## Tips for getting to know the code base
- Check the JSDoc block right above the function definition to understand what it does. It contains a short description of each function argument and what it does.
- Check the callsites of a function to understand how it's used. Modern editors/IDEs allow you to quickly find those, or use the plain old search feature instead.
## Benchmarks
We have a benchmark suite that we use to measure the performance of Preact. Our benchmark suite lives in our [preactjs/benchmarks repository](https://github.com/preactjs/benchmarks), but is included here as Git submodule. To run the benchmarks, first ensure [PNPM](https://pnpm.io/installation) is installed on your system and initialize and setup the submodule (it uses `pnpm` as a package manager):
```bash
pnpm -v # Make sure pnpm is installed
git submodule update --init --recursive
cd benchmarks
pnpm i
```
Then you can run the benchmarks:
```bash
# In the benchmarks folder
pnpm run bench
```
Checkout the README in the benchmarks folder for more information on running benchmarks.
> **Note:** When switching branches, git submodules are not automatically updated to the commit of the new branch - it stays at the commit of the previous branch. This can be a feature! It allows you to work in different branches with the latest versions of the benchmarks - especially if you have made changes to the benchmarks.
>
> However if you want to switch branches and also update the benchmarks to the latest commit of the new branch, you can run `git submodule update --recursive` after switching branches, or run `git checkout --recurse-submodules` when checking out a new branch.
## FAQ
### Why does the JSDoc use TypeScript syntax to specify types?
Several members of the team are very fond of TypeScript and we wanted to leverage as many of its advantages, like improved autocompletion, for Preact. We even attempted to port Preact to TypeScript a few times, but we ran into many issues with the DOM typings. Those would force us to fill our codebase with many `any` castings, making our code very noisy.
Luckily TypeScript has a mode where it can somewhat reliably typecheck JavaScript code by reusing the types defined in JSDoc blocks. It's not perfect and it often has trouble inferring the correct types the further one strays away from the function arguments, but it's good enough that it helps us a lot with autocompletion. Another plus is that we can make sure that our TypeScript definitons are correct at the same time.
Check out the [official TypeScript documentation](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html) for more information.
_Note that we have separate tests for our TypeScript definition files. We only use `ts-check` for local development and don't check it anywhere else like on the CI._
### Why does the code base often use `let` instead of `const`?
There is no real reason for that other a historical one. Back before auto-formatting via prettier was a thing and minifiers weren't as advanced as they are today we used a pretty terse code-style. The code-style deliberately was aimed at making code look as concise and short as possible. The `let` keyword is a bit shorter than `const` to write, so we only used that. This was done only for stylistic reasons.
This helped our minds to not lose sight of focusing on size, but made it difficult for newcomers to start contributing to Preact. For that reason alone we switched to `prettier` and loosened our rule regarding usage of `let` or `const`. Today we use both, but you can still find many existing places where `let` is still in use.
In the end there is no effect on size regardless if you use `const`, `let` or use both. Our code is downtranspiled to `ES5` for npm so both will be replaced with `var` anyways. Therefore it doesn't really matter at all which one is used in our codebase.
This will only become important once shipping modern JavaScript code on npm becomes a thing and bundlers follow suit.
## How to create a good bug report
To be able to fix issues we need to see them on our machine. This is only possible when we can reproduce the error. The easiest way to do that is narrow down the problem to specific components or combination of them. This can be done by removing as much unrelated code as possible.
The perfect way to do that is to make a [codesandbox](https://codesandbox.io/). That way you can easily share the problematic code and ensure that others can see the same issue you are seeing.
For us a [codesandbox](https://codesandbox.io/) says more than a 1000 words :tada:
## I have more questions on how to contribute to Preact. How can I reach you?
We closely watch our issues and have a pretty active [Slack workspace](https://chat.preactjs.com/). Nearly all our communication happens via these two forms of communication.
## Releasing Preact (Maintainers only)
This guide is intended for core team members that have the necessary
rights to publish new releases on npm.
Before using the automated npm publishing flow, make sure npm trusted publishing is configured for the `preactjs/preact` repository, the `release.yml` workflow, and the `npm` environment. The GitHub `npm` environment should require reviewer approval, and repository rules should protect `10.*` tags.
1. Make a PR where **only** the version number is incremented in `package.json` and everywhere else. A simple search and replace works. (note: We follow `SemVer` conventions)
2. Wait until the PR is approved and merged.
3. Switch back to the `v10.x` branch and pull the merged PR
4. Create and push a tag for the new version you want to publish:
1. `git tag 10.0.0`
2. `git push origin 10.0.0`
5. Wait for the Release workflow to reach the `npm` environment approval gate, approve it, and let it complete
- It'll validate that the tag matches the package version, create a draft release, upload the built npm package as a release asset, and publish it to npm.
- Stable releases publish to the `latest` npm dist-tag; prereleases publish to the approved prerelease dist-tag (`alpha`, `beta`, `rc`, or `next`).
6. [Fill in the release notes](#writing-release-notes) in GitHub and publish them
7. Tweet it out
## Legacy Releases (8.x)
> **ATTENTION:** Make sure that you've cleared the project correctly
> when switching from a 10.x branch.
0. Run `rm -rf dist node_modules && npm i` to make sure to have the correct dependencies.
1. [Write the release notes](#writing-release-notes) and keep them as a draft in GitHub
1. I'd recommend writing them in an offline editor because each edit to a draft will change the URL in GitHub.
2. Make a PR where **only** the version number is incremented in `package.json` (note: We follow `SemVer` conventions)
3. Wait until the PR is approved and merged.
4. Switch back to the `main` branch and pull the merged PR
5. Run `npm run build && npm publish`
1. Make sure you have 2FA enabled in npm, otherwise the above command will fail.
2. If you're doing a pre-release add `--tag next` to the `npm publish` command to publish it under a different tag (default is `latest`)
6. Publish the release notes and create the correct git tag.
7. Tweet it out
## Writing release notes
The release notes have become a sort of tiny blog post about what's
happening in preact-land. The title usually has this format:
```txt
Version Name
```
Example:
```txt
10.0.0-beta.1 Los Compresseros
```
The name is optional, we just have fun finding creative names :wink:
To keep them interesting we try to be as
concise as possible and to just reflect where we are. There are some
rules we follow while writing them:
- Be nice, use a positive tone. Avoid negative words
- Show, don't just tell.
- Be honest.
- Don't write too much, keep it simple and short.
- Avoid making promises and don't overpromise. That leads to unhappy users
- Avoid framework comparisons if possible
- Highlight awesome community contributions (or great issue reports)
- If in doubt, praise the users.
After this section we typically follow with a changelog part that's
divided into 4 groups in order of importance for the user:
- Features
- Bug Fixes
- Typings
- Maintenance
We generate it via this handy cli program: [changelogged](https://github.com/marvinhagemeister/changelogged). It will collect and format
the descriptions of all PRs that have been merged between two tags.
The usual command is `changelogged 10.0.0-rc.2..HEAD` similar to how
you'd diff two points in time with git. This will get you 90% there,
but you still need to divide it into groups. It's also a good idea
to unify the formatting of the descriptions, so that they're easier
to read and don't look like a mess.
preact-10.29.2/LICENSE 0000664 0000000 0000000 00000002077 15202310201 0014140 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2015-present Jason Miller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
preact-10.29.2/README.md 0000664 0000000 0000000 00000034154 15202310201 0014413 0 ustar 00root root 0000000 0000000
Fast 3kB alternative to React with the same modern API.
**All the power of Virtual DOM components, without the overhead:**
- Familiar React API & patterns: ES6 Class, hooks, and Functional Components
- Extensive React compatibility via a simple [preact/compat] alias
- Everything you need: JSX, VDOM, [DevTools], HMR, SSR.
- Highly optimized diff algorithm and seamless hydration from Server Side Rendering
- Supports all modern browsers and IE11
- Transparent asynchronous rendering with a pluggable scheduler
### 💁 More information at the [Preact Website ➞](https://preactjs.com)
You can find some awesome libraries in the [awesome-preact list](https://github.com/preactjs/awesome-preact) :sunglasses:
---
## Getting Started
> 💁 _**Note:** You [don't need ES2015 to use Preact](https://github.com/developit/preact-in-es3)... but give it a try!_
#### Tutorial: Building UI with Preact
With Preact, you create user interfaces by assembling trees of components and elements. Components are functions or classes that return a description of what their tree should output. These descriptions are typically written in [JSX](https://facebook.github.io/jsx/) (shown underneath), or [HTM](https://github.com/developit/htm) which leverages standard JavaScript Tagged Templates. Both syntaxes can express trees of elements with "props" (similar to HTML attributes) and children.
To get started using Preact, first look at the render() function. This function accepts a tree description and creates the structure described. Next, it appends this structure to a parent DOM element provided as the second argument. Future calls to render() will reuse the existing tree and update it in-place in the DOM. Internally, render() will calculate the difference from previous outputted structures in an attempt to perform as few DOM operations as possible.
```js
import { h, render } from 'preact';
// Tells babel to use h for JSX. It's better to configure this globally.
// See https://babeljs.io/docs/en/babel-plugin-transform-react-jsx#usage
// In tsconfig you can specify this with the jsxFactory
/** @jsx h */
// create our tree and append it to document.body:
render(
Hello
,
document.body
);
// update the tree in-place:
render(
Hello World!
,
document.body
);
// ^ this second invocation of render(...) will use a single DOM call to update the text of the
```
Hooray! render() has taken our structure and output a User Interface! This approach demonstrates a simple case, but would be difficult to use as an application grows in complexity. Each change would be forced to calculate the difference between the current and updated structure for the entire application. Components can help here – by dividing the User Interface into nested Components each can calculate their difference from their mounted point. Here's an example:
```js
import { render, h } from 'preact';
import { useState } from 'preact/hooks';
/** @jsx h */
const App = () => {
const [input, setInput] = useState('');
return (
Do you agree to the statement: "Preact is awesome"?
setInput(e.target.value)} />
);
};
render(, document.body);
```
---
## Sponsors
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/preact#sponsor)]
## Backers
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/preact#backer)]
---
## License
MIT
[](https://preactjs.com)
[preact/compat]: https://github.com/preactjs/preact/tree/main/compat
[hyperscript]: https://github.com/dominictarr/hyperscript
[DevTools]: https://github.com/preactjs/preact-devtools
preact-10.29.2/babel.config.js 0000664 0000000 0000000 00000001736 15202310201 0016003 0 ustar 00root root 0000000 0000000 module.exports = function (api) {
api.cache(true);
const noModules = String(process.env.BABEL_NO_MODULES) === 'true';
const rename = {};
const mangle = require('./mangle.json');
for (let prop in mangle.props.props) {
let name = prop;
if (name[0] === '$') {
name = name.slice(1);
}
rename[name] = mangle.props.props[prop];
}
return {
presets: [
[
'@babel/preset-env',
{
loose: true,
// Don't transform modules when using esbuild
modules: noModules ? false : 'auto',
exclude: ['@babel/plugin-transform-typeof-symbol'],
targets: {
browsers: ['last 2 versions', 'IE >= 9']
}
}
]
],
plugins: [
'@babel/plugin-transform-react-jsx',
['babel-plugin-transform-rename-properties', { rename }]
],
include: ['**/src/**/*.js', '**/test/**/*.js', '**/test/**/*.jsx'],
overrides: [
{
test: /(component-stack|debug)\.test\.jsx?$/,
plugins: ['@babel/plugin-transform-react-jsx-source']
}
]
};
};
preact-10.29.2/benchmarks/ 0000775 0000000 0000000 00000000000 15202310201 0015242 5 ustar 00root root 0000000 0000000 preact-10.29.2/compat/ 0000775 0000000 0000000 00000000000 15202310201 0014410 5 ustar 00root root 0000000 0000000 preact-10.29.2/compat/LICENSE 0000664 0000000 0000000 00000002077 15202310201 0015423 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2015-present Jason Miller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
preact-10.29.2/compat/client.d.ts 0000664 0000000 0000000 00000000621 15202310201 0016457 0 ustar 00root root 0000000 0000000 // Intentionally not using a relative path to take advantage of
// the TS version resolution mechanism
import * as preact from 'preact';
export function createRoot(container: preact.ContainerNode): {
render(children: preact.ComponentChild): void;
unmount(): void;
};
export function hydrateRoot(
container: preact.ContainerNode,
children: preact.ComponentChild
): ReturnType;
preact-10.29.2/compat/client.js 0000664 0000000 0000000 00000000737 15202310201 0016233 0 ustar 00root root 0000000 0000000 const { render, hydrate, unmountComponentAtNode } = require('preact/compat');
function createRoot(container) {
return {
// eslint-disable-next-line
render: function (children) {
render(children, container);
},
// eslint-disable-next-line
unmount: function () {
unmountComponentAtNode(container);
}
};
}
exports.createRoot = createRoot;
exports.hydrateRoot = function (container, children) {
hydrate(children, container);
return createRoot(container);
};
preact-10.29.2/compat/client.mjs 0000664 0000000 0000000 00000000751 15202310201 0016404 0 ustar 00root root 0000000 0000000 import { render, hydrate, unmountComponentAtNode } from 'preact/compat';
export function createRoot(container) {
return {
// eslint-disable-next-line
render: function (children) {
render(children, container);
},
// eslint-disable-next-line
unmount: function () {
unmountComponentAtNode(container);
}
};
}
export function hydrateRoot(container, children) {
hydrate(children, container);
return createRoot(container);
}
export default {
createRoot,
hydrateRoot
};
preact-10.29.2/compat/jsx-dev-runtime.js 0000664 0000000 0000000 00000000113 15202310201 0020002 0 ustar 00root root 0000000 0000000 require('preact/compat');
module.exports = require('preact/jsx-runtime');
preact-10.29.2/compat/jsx-dev-runtime.mjs 0000664 0000000 0000000 00000000075 15202310201 0020166 0 ustar 00root root 0000000 0000000 import 'preact/compat';
export * from 'preact/jsx-runtime';
preact-10.29.2/compat/jsx-runtime.js 0000664 0000000 0000000 00000000113 15202310201 0017226 0 ustar 00root root 0000000 0000000 require('preact/compat');
module.exports = require('preact/jsx-runtime');
preact-10.29.2/compat/jsx-runtime.mjs 0000664 0000000 0000000 00000000075 15202310201 0017412 0 ustar 00root root 0000000 0000000 import 'preact/compat';
export * from 'preact/jsx-runtime';
preact-10.29.2/compat/mangle.json 0000664 0000000 0000000 00000001254 15202310201 0016550 0 ustar 00root root 0000000 0000000 {
"help": {
"what is this file?": "It controls protected/private property mangling so that minified builds have consistent property names.",
"why are there duplicate minified properties?": "Most properties are only used on one type of objects, so they can have the same name since they will never collide. Doing this reduces size."
},
"minify": {
"mangle": {
"properties": {
"regex": "^_[^_]",
"reserved": [
"__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
"__REACT_DEVTOOLS_GLOBAL_HOOK__",
"__PREACT_DEVTOOLS__",
"_renderers",
"__source",
"__self"
]
}
}
}
}
preact-10.29.2/compat/package.json 0000664 0000000 0000000 00000002514 15202310201 0016700 0 ustar 00root root 0000000 0000000 {
"name": "preact-compat",
"amdName": "preactCompat",
"version": "4.0.0",
"private": true,
"description": "A React compatibility layer for Preact",
"main": "dist/compat.js",
"module": "dist/compat.module.js",
"umd:main": "dist/compat.umd.js",
"source": "src/index.js",
"types": "src/index.d.ts",
"license": "MIT",
"mangle": {
"regex": "^_"
},
"peerDependencies": {
"preact": "^10.0.0"
},
"exports": {
".": {
"types": "./src/index.d.ts",
"browser": "./dist/compat.module.js",
"umd": "./dist/compat.umd.js",
"import": "./dist/compat.mjs",
"require": "./dist/compat.js"
},
"./client": {
"types": "./client.d.ts",
"import": "./client.mjs",
"require": "./client.js"
},
"./server": {
"browser": "./server.browser.js",
"import": "./server.mjs",
"require": "./server.js"
},
"./jsx-runtime": {
"import": "./jsx-runtime.mjs",
"require": "./jsx-runtime.js"
},
"./jsx-dev-runtime": {
"import": "./jsx-dev-runtime.mjs",
"require": "./jsx-dev-runtime.js"
},
"./scheduler": {
"import": "./scheduler.mjs",
"require": "./scheduler.js"
},
"./test-utils": {
"import": "./test-utils.mjs",
"require": "./test-utils.js"
},
"./package.json": "./package.json"
}
}
preact-10.29.2/compat/scheduler.js 0000664 0000000 0000000 00000000534 15202310201 0016726 0 ustar 00root root 0000000 0000000 // see scheduler.mjs
function unstable_runWithPriority(priority, callback) {
return callback();
}
module.exports = {
unstable_ImmediatePriority: 1,
unstable_UserBlockingPriority: 2,
unstable_NormalPriority: 3,
unstable_LowPriority: 4,
unstable_IdlePriority: 5,
unstable_runWithPriority,
unstable_now: performance.now.bind(performance)
};
preact-10.29.2/compat/scheduler.mjs 0000664 0000000 0000000 00000001400 15202310201 0017074 0 ustar 00root root 0000000 0000000 /* eslint-disable */
// This file includes experimental React APIs exported from the "scheduler"
// npm package. Despite being explicitely marked as unstable some libraries
// already make use of them. This file is not a full replacement for the
// scheduler package, but includes the necessary shims to make those libraries
// work with Preact.
export var unstable_ImmediatePriority = 1;
export var unstable_UserBlockingPriority = 2;
export var unstable_NormalPriority = 3;
export var unstable_LowPriority = 4;
export var unstable_IdlePriority = 5;
/**
* @param {number} priority
* @param {() => void} callback
*/
export function unstable_runWithPriority(priority, callback) {
return callback();
}
export var unstable_now = performance.now.bind(performance);
preact-10.29.2/compat/server.browser.js 0000664 0000000 0000000 00000000353 15202310201 0017737 0 ustar 00root root 0000000 0000000 import { renderToString } from 'preact-render-to-string';
export {
renderToString,
renderToString as renderToStaticMarkup
} from 'preact-render-to-string';
export default {
renderToString,
renderToStaticMarkup: renderToString
};
preact-10.29.2/compat/server.js 0000664 0000000 0000000 00000002044 15202310201 0016254 0 ustar 00root root 0000000 0000000 /* eslint-disable */
var renderToString;
try {
const mod = require('preact-render-to-string');
renderToString = mod.default || mod.renderToString || mod;
} catch (e) {
throw Error(
'renderToString() error: missing "preact-render-to-string" dependency.'
);
}
var renderToReadableStream;
try {
const mod = require('preact-render-to-string/stream');
renderToReadableStream = mod.default || mod.renderToReadableStream || mod;
} catch (e) {
throw Error(
'renderToReadableStream() error: update "preact-render-to-string" dependency to at least 6.5.0.'
);
}
var renderToPipeableStream;
try {
const mod = require('preact-render-to-string/stream-node');
renderToPipeableStream = mod.default || mod.renderToPipeableStream || mod;
} catch (e) {
throw Error(
'renderToPipeableStream() error: update "preact-render-to-string" dependency to at least 6.5.0.'
);
}
module.exports = {
renderToString: renderToString,
renderToStaticMarkup: renderToString,
renderToPipeableStream: renderToPipeableStream,
renderToReadableStream: renderToReadableStream
};
preact-10.29.2/compat/server.mjs 0000664 0000000 0000000 00000001113 15202310201 0016425 0 ustar 00root root 0000000 0000000 import { renderToString } from 'preact-render-to-string';
import { renderToPipeableStream } from 'preact-render-to-string/stream-node';
import { renderToReadableStream } from 'preact-render-to-string/stream';
export {
renderToString,
renderToString as renderToStaticMarkup
} from 'preact-render-to-string';
export { renderToPipeableStream } from 'preact-render-to-string/stream-node';
export { renderToReadableStream } from 'preact-render-to-string/stream';
export default {
renderToString,
renderToStaticMarkup: renderToString,
renderToPipeableStream,
renderToReadableStream
};
preact-10.29.2/compat/src/ 0000775 0000000 0000000 00000000000 15202310201 0015177 5 ustar 00root root 0000000 0000000 preact-10.29.2/compat/src/Children.js 0000664 0000000 0000000 00000001052 15202310201 0017263 0 ustar 00root root 0000000 0000000 import { toChildArray } from 'preact';
const mapFn = (children, fn) => {
if (children == null) return null;
return toChildArray(toChildArray(children).map(fn));
};
// This API is completely unnecessary for Preact, so it's basically passthrough.
export const Children = {
map: mapFn,
forEach: mapFn,
count(children) {
return children ? toChildArray(children).length : 0;
},
only(children) {
const normalized = toChildArray(children);
if (normalized.length !== 1) throw 'Children.only';
return normalized[0];
},
toArray: toChildArray
};
preact-10.29.2/compat/src/PureComponent.js 0000664 0000000 0000000 00000001053 15202310201 0020332 0 ustar 00root root 0000000 0000000 import { Component } from 'preact';
import { shallowDiffers } from './util';
/**
* Component class with a predefined `shouldComponentUpdate` implementation
*/
export function PureComponent(p, c) {
this.props = p;
this.context = c;
}
PureComponent.prototype = new Component();
// Some third-party libraries check if this property is present
PureComponent.prototype.isPureReactComponent = true;
PureComponent.prototype.shouldComponentUpdate = function (props, state) {
return shallowDiffers(this.props, props) || shallowDiffers(this.state, state);
};
preact-10.29.2/compat/src/forwardRef.js 0000664 0000000 0000000 00000002523 15202310201 0017640 0 ustar 00root root 0000000 0000000 import { options } from 'preact';
import { assign } from './util';
let oldDiffHook = options._diff;
options._diff = vnode => {
if (vnode.type && vnode.type._forwarded && vnode.ref) {
vnode.props.ref = vnode.ref;
vnode.ref = null;
}
if (oldDiffHook) oldDiffHook(vnode);
};
export const REACT_FORWARD_SYMBOL =
(typeof Symbol != 'undefined' &&
Symbol.for &&
Symbol.for('react.forward_ref')) ||
0xf47;
/**
* Pass ref down to a child. This is mainly used in libraries with HOCs that
* wrap components. Using `forwardRef` there is an easy way to get a reference
* of the wrapped component instead of one of the wrapper itself.
* @param {import('./index').ForwardFn} fn
* @returns {import('./internal').FunctionComponent}
*/
export function forwardRef(fn) {
function Forwarded(props) {
let clone = assign({}, props);
delete clone.ref;
return fn(clone, props.ref || null);
}
// mobx-react checks for this being present
Forwarded.$$typeof = REACT_FORWARD_SYMBOL;
// mobx-react heavily relies on implementation details.
// It expects an object here with a `render` property,
// and prototype.render will fail. Without this
// mobx-react throws.
Forwarded.render = fn;
Forwarded.prototype.isReactComponent = Forwarded._forwarded = true;
Forwarded.displayName = 'ForwardRef(' + (fn.displayName || fn.name) + ')';
return Forwarded;
}
preact-10.29.2/compat/src/hooks.js 0000664 0000000 0000000 00000003204 15202310201 0016657 0 ustar 00root root 0000000 0000000 import { useState, useLayoutEffect, useEffect } from 'preact/hooks';
import { is } from './util';
/**
* This is taken from https://github.com/facebook/react/blob/main/packages/use-sync-external-store/src/useSyncExternalStoreShimClient.js#L84
* on a high level this cuts out the warnings, ... and attempts a smaller implementation
* @typedef {{ _value: any; _getSnapshot: () => any }} Store
*/
export function useSyncExternalStore(subscribe, getSnapshot) {
const value = getSnapshot();
/**
* @typedef {{ _instance: Store }} StoreRef
* @type {[StoreRef, (store: StoreRef) => void]}
*/
const [{ _instance }, forceUpdate] = useState({
_instance: { _value: value, _getSnapshot: getSnapshot }
});
useLayoutEffect(() => {
_instance._value = value;
_instance._getSnapshot = getSnapshot;
if (didSnapshotChange(_instance)) {
forceUpdate({ _instance });
}
}, [subscribe, value, getSnapshot]);
useEffect(() => {
if (didSnapshotChange(_instance)) {
forceUpdate({ _instance });
}
return subscribe(() => {
if (didSnapshotChange(_instance)) {
forceUpdate({ _instance });
}
});
}, [subscribe]);
return value;
}
/** @type {(inst: Store) => boolean} */
function didSnapshotChange(inst) {
try {
return !is(inst._value, inst._getSnapshot());
} catch (error) {
return true;
}
}
export function startTransition(cb) {
cb();
}
export function useDeferredValue(val) {
return val;
}
export function useTransition() {
return [false, startTransition];
}
// TODO: in theory this should be done after a VNode is diffed as we want to insert
// styles/... before it attaches
export const useInsertionEffect = useLayoutEffect;
preact-10.29.2/compat/src/index.d.ts 0000664 0000000 0000000 00000033274 15202310201 0017111 0 ustar 00root root 0000000 0000000 import * as _hooks from '../../hooks';
// Intentionally not using a relative path to take advantage of
// the TS version resolution mechanism
import * as preact from 'preact';
import { JSXInternal } from '../../src/jsx';
import * as _Suspense from './suspense';
import * as _SuspenseList from './suspense-list';
// export default React;
export = React;
export as namespace React;
declare namespace React {
// Export JSX
export import JSX = JSXInternal;
// Hooks
export import CreateHandle = _hooks.CreateHandle;
export import EffectCallback = _hooks.EffectCallback;
export import Inputs = _hooks.Inputs;
export import PropRef = _hooks.PropRef;
export import Reducer = _hooks.Reducer;
export import Dispatch = _hooks.Dispatch;
export import SetStateAction = _hooks.StateUpdater;
export import useCallback = _hooks.useCallback;
export import useContext = _hooks.useContext;
export import useDebugValue = _hooks.useDebugValue;
export import useEffect = _hooks.useEffect;
export import useImperativeHandle = _hooks.useImperativeHandle;
export import useId = _hooks.useId;
export import useLayoutEffect = _hooks.useLayoutEffect;
export import useMemo = _hooks.useMemo;
export import useReducer = _hooks.useReducer;
export import useRef = _hooks.useRef;
export import useState = _hooks.useState;
// React 18 hooks
export import useInsertionEffect = _hooks.useLayoutEffect;
export function useTransition(): [false, typeof startTransition];
export function useDeferredValue(val: T): T;
export function useSyncExternalStore(
subscribe: (flush: () => void) => () => void,
getSnapshot: () => T
): T;
// Preact Defaults
export import Context = preact.Context;
export import ContextType = preact.ContextType;
export import RefObject = preact.RefObject;
export import Component = preact.Component;
export import FunctionComponent = preact.FunctionComponent;
export import ComponentType = preact.ComponentType;
export import ComponentClass = preact.ComponentClass;
export import FC = preact.FunctionComponent;
export import createContext = preact.createContext;
export import Ref = preact.Ref;
export import createRef = preact.createRef;
export import Fragment = preact.Fragment;
export import createElement = preact.createElement;
export import cloneElement = preact.cloneElement;
export import ComponentProps = preact.ComponentProps;
export import ReactNode = preact.ComponentChild;
export import ReactElement = preact.VNode;
export import Consumer = preact.Consumer;
export import ErrorInfo = preact.ErrorInfo;
export import Key = preact.Key;
// Suspense
export import Suspense = _Suspense.Suspense;
export import lazy = _Suspense.lazy;
export import SuspenseList = _SuspenseList.SuspenseList;
// Compat
export import StrictMode = preact.Fragment;
export const version: string;
export function startTransition(cb: () => void): void;
// HTML
export interface HTMLAttributes<
T extends EventTarget
> extends JSXInternal.HTMLAttributes {}
export interface HTMLProps
extends JSXInternal.AllHTMLAttributes, preact.ClassAttributes {}
export interface AllHTMLAttributes<
T extends EventTarget
> extends JSXInternal.AllHTMLAttributes {}
export import DetailedHTMLProps = JSXInternal.DetailedHTMLProps;
export import CSSProperties = JSXInternal.CSSProperties;
export interface SVGProps
extends JSXInternal.SVGAttributes, preact.ClassAttributes {}
interface SVGAttributes<
T extends EventTarget = SVGElement
> extends JSXInternal.SVGAttributes {}
interface ReactSVG extends JSXInternal.IntrinsicSVGElements {}
export import AriaAttributes = JSXInternal.AriaAttributes;
export import HTMLAttributeReferrerPolicy = JSXInternal.HTMLAttributeReferrerPolicy;
export import HTMLAttributeAnchorTarget = JSXInternal.HTMLAttributeAnchorTarget;
export import HTMLInputTypeAttribute = JSXInternal.HTMLInputTypeAttribute;
export import HTMLAttributeCrossOrigin = JSXInternal.HTMLAttributeCrossOrigin;
export import AnchorHTMLAttributes = JSXInternal.AnchorHTMLAttributes;
export import AudioHTMLAttributes = JSXInternal.AudioHTMLAttributes;
export import AreaHTMLAttributes = JSXInternal.AreaHTMLAttributes;
export import BaseHTMLAttributes = JSXInternal.BaseHTMLAttributes;
export import BlockquoteHTMLAttributes = JSXInternal.BlockquoteHTMLAttributes;
export import ButtonHTMLAttributes = JSXInternal.ButtonHTMLAttributes;
export import CanvasHTMLAttributes = JSXInternal.CanvasHTMLAttributes;
export import ColHTMLAttributes = JSXInternal.ColHTMLAttributes;
export import ColgroupHTMLAttributes = JSXInternal.ColgroupHTMLAttributes;
export import DataHTMLAttributes = JSXInternal.DataHTMLAttributes;
export import DetailsHTMLAttributes = JSXInternal.DetailsHTMLAttributes;
export import DelHTMLAttributes = JSXInternal.DelHTMLAttributes;
export import DialogHTMLAttributes = JSXInternal.DialogHTMLAttributes;
export import EmbedHTMLAttributes = JSXInternal.EmbedHTMLAttributes;
export import FieldsetHTMLAttributes = JSXInternal.FieldsetHTMLAttributes;
export import FormHTMLAttributes = JSXInternal.FormHTMLAttributes;
export import IframeHTMLAttributes = JSXInternal.IframeHTMLAttributes;
export import ImgHTMLAttributes = JSXInternal.ImgHTMLAttributes;
export import InsHTMLAttributes = JSXInternal.InsHTMLAttributes;
export import InputHTMLAttributes = JSXInternal.InputHTMLAttributes;
export import KeygenHTMLAttributes = JSXInternal.KeygenHTMLAttributes;
export import LabelHTMLAttributes = JSXInternal.LabelHTMLAttributes;
export import LiHTMLAttributes = JSXInternal.LiHTMLAttributes;
export import LinkHTMLAttributes = JSXInternal.LinkHTMLAttributes;
export import MapHTMLAttributes = JSXInternal.MapHTMLAttributes;
export import MenuHTMLAttributes = JSXInternal.MenuHTMLAttributes;
export import MediaHTMLAttributes = JSXInternal.MediaHTMLAttributes;
export import MetaHTMLAttributes = JSXInternal.MetaHTMLAttributes;
export import MeterHTMLAttributes = JSXInternal.MeterHTMLAttributes;
export import QuoteHTMLAttributes = JSXInternal.QuoteHTMLAttributes;
export import ObjectHTMLAttributes = JSXInternal.ObjectHTMLAttributes;
export import OlHTMLAttributes = JSXInternal.OlHTMLAttributes;
export import OptgroupHTMLAttributes = JSXInternal.OptgroupHTMLAttributes;
export import OptionHTMLAttributes = JSXInternal.OptionHTMLAttributes;
export import OutputHTMLAttributes = JSXInternal.OutputHTMLAttributes;
export import ParamHTMLAttributes = JSXInternal.ParamHTMLAttributes;
export import ProgressHTMLAttributes = JSXInternal.ProgressHTMLAttributes;
export import SlotHTMLAttributes = JSXInternal.SlotHTMLAttributes;
export import ScriptHTMLAttributes = JSXInternal.ScriptHTMLAttributes;
export import SelectHTMLAttributes = JSXInternal.SelectHTMLAttributes;
export import SourceHTMLAttributes = JSXInternal.SourceHTMLAttributes;
export import StyleHTMLAttributes = JSXInternal.StyleHTMLAttributes;
export import TableHTMLAttributes = JSXInternal.TableHTMLAttributes;
export import TextareaHTMLAttributes = JSXInternal.TextareaHTMLAttributes;
export import TdHTMLAttributes = JSXInternal.TdHTMLAttributes;
export import ThHTMLAttributes = JSXInternal.ThHTMLAttributes;
export import TimeHTMLAttributes = JSXInternal.TimeHTMLAttributes;
export import TrackHTMLAttributes = JSXInternal.TrackHTMLAttributes;
export import VideoHTMLAttributes = JSXInternal.VideoHTMLAttributes;
// Events
export import TargetedEvent = JSXInternal.TargetedEvent;
export import ChangeEvent = JSXInternal.TargetedEvent;
export import ClipboardEvent = JSXInternal.TargetedClipboardEvent;
export import CompositionEvent = JSXInternal.TargetedCompositionEvent;
export import DragEvent = JSXInternal.TargetedDragEvent;
export import PointerEvent = JSXInternal.TargetedPointerEvent;
export import FocusEvent = JSXInternal.TargetedFocusEvent;
export import FormEvent = JSXInternal.TargetedEvent;
export import InvalidEvent = JSXInternal.TargetedEvent;
export import KeyboardEvent = JSXInternal.TargetedKeyboardEvent;
export import MouseEvent = JSXInternal.TargetedMouseEvent;
export import TouchEvent = JSXInternal.TargetedTouchEvent;
export import UIEvent = JSXInternal.TargetedUIEvent;
export import AnimationEvent = JSXInternal.TargetedAnimationEvent;
export import TransitionEvent = JSXInternal.TargetedTransitionEvent;
// Event Handler Types
export import EventHandler = JSXInternal.EventHandler;
export import ChangeEventHandler = JSXInternal.GenericEventHandler;
export import ClipboardEventHandler = JSXInternal.ClipboardEventHandler;
export import CompositionEventHandler = JSXInternal.CompositionEventHandler;
export import DragEventHandler = JSXInternal.DragEventHandler;
export import PointerEventHandler = JSXInternal.PointerEventHandler;
export import FocusEventHandler = JSXInternal.FocusEventHandler;
export import FormEventHandler = JSXInternal.GenericEventHandler;
export import InvalidEventHandler = JSXInternal.GenericEventHandler;
export import KeyboardEventHandler = JSXInternal.KeyboardEventHandler;
export import MouseEventHandler = JSXInternal.MouseEventHandler;
export import TouchEventHandler = JSXInternal.TouchEventHandler;
export import UIEventHandler = JSXInternal.UIEventHandler;
export import AnimationEventHandler = JSXInternal.AnimationEventHandler;
export import TransitionEventHandler = JSXInternal.TransitionEventHandler;
export function createPortal(
vnode: preact.ComponentChildren,
container: preact.ContainerNode
): preact.VNode;
export function render(
vnode: preact.ComponentChild,
parent: preact.ContainerNode,
callback?: () => void
): Component | null;
export function hydrate(
vnode: preact.ComponentChild,
parent: preact.ContainerNode,
callback?: () => void
): Component | null;
export function unmountComponentAtNode(
container: preact.ContainerNode
): boolean;
export function createFactory(
type: preact.VNode['type']
): (
props?: any,
...children: preact.ComponentChildren[]
) => preact.VNode;
export function isValidElement(element: any): boolean;
export function isFragment(element: any): boolean;
export function isMemo(element: any): boolean;
export function findDOMNode(
component: preact.Component | Element
): Element | null;
export abstract class PureComponent<
P = {},
S = {},
SS = any
> extends preact.Component
{
isPureReactComponent: boolean;
}
export type MemoExoticComponent> =
preact.FunctionComponent> & {
readonly type: C;
};
export function memo
| undefined;
}
export function forwardRef(
fn: ForwardRefRenderFunction
): preact.FunctionalComponent & { ref?: preact.Ref }>;
export type PropsWithoutRef
= Omit
;
interface MutableRefObject {
current: T;
}
export type ForwardedRef =
| ((instance: T | null) => void)
| MutableRefObject
| null;
export type ElementType<
P = any,
Tag extends keyof JSX.IntrinsicElements = keyof JSX.IntrinsicElements
> =
| { [K in Tag]: P extends JSX.IntrinsicElements[K] ? K : never }[Tag]
| ComponentType
;
export type ComponentPropsWithoutRef = PropsWithoutRef<
ComponentProps
>;
export type ComponentPropsWithRef = C extends new (
props: infer P
) => Component
? PropsWithoutRef
`);
expect(lifecycles.componentWillMount).to.have.been.calledOnce;
expect(lifecycles.componentDidMount).to.have.been.calledOnce;
// TODO: This is called thrice since the cDU queued up after the second
// increment is never cleared once the component suspends. So when it
// resumes and the component is rerendered, we queue up another cDU so
// cDU is called an extra time.
expect(lifecycles.componentDidUpdate).to.have.been.calledThrice;
expect(lifecycles.componentWillUnmount).to.not.have.been.called;
});
});
it('should not call lifecycle methods when a sibling suspends', () => {
class LifecycleLogger extends Component {
render() {
return
`);
});
});
// TODO: Revisit later. Consider using an "options.commit" plugin to detect
// when a suspended component has rerendered and trigger a rerender on the
// parent Suspense
it.skip('should allow suspended children to update', () => {
const log = [];
class Logger extends Component {
constructor(props) {
super(props);
log.push('construct');
}
render({ children }) {
log.push('render');
return children;
}
}
/** @type {Suspender} */
let suspender;
class Suspender extends Component {
constructor(props) {
super(props);
this.state = { promise: new Promise(() => {}) };
suspender = this;
}
unsuspend() {
this.setState({ promise: null });
}
render() {
if (this.state.promise) {
throw this.state.promise;
}
return
Suspender un-suspended
;
}
}
render(
fallback
}>
,
scratch
);
expect(log).to.eql(['construct', 'render']);
expect(scratch.innerHTML).to.eql('');
// this rerender is needed because of Suspense issuing a forceUpdate itself
rerender();
expect(scratch.innerHTML).to.eql('
'
);
});
// TODO: Revisit later. Consider using an "options.commit" plugin to detect
// when a suspended component has rerendered and trigger a rerender on the
// parent Suspense
it.skip('should allow multiple suspended children to update', () => {
function createSuspender() {
let suspender;
class Suspender extends Component {
constructor(props) {
super(props);
this.state = { promise: new Promise(() => {}) };
suspender = this;
}
unsuspend(content) {
this.setState({ promise: null, content });
}
render() {
if (this.state.promise) {
throw this.state.promise;
}
return this.state.content;
}
}
return [content => suspender.unsuspend(content), Suspender];
}
const [unsuspender1, Suspender1] = createSuspender();
const [unsuspender2, Suspender2] = createSuspender();
render(
fallback}>
,
scratch
);
expect(scratch.innerHTML).to.eql('');
// this rerender is needed because of Suspense issuing a forceUpdate itself
rerender();
expect(scratch.innerHTML).to.eql('
'
);
});
// TODO: Revisit later. Consider using an "options.commit" plugin to detect
// when a suspended component has rerendered and trigger a rerender on the
// parent Suspense
it.skip('should allow suspended children children to update', () => {
function Suspender({ promise, content }) {
if (promise) {
throw promise;
}
return content;
}
/** @type {Component} */
let parent;
class Parent extends Component {
constructor(props) {
super(props);
this.state = { promise: new Promise(() => {}), condition: true };
parent = this;
}
render() {
const { condition, promise, content } = this.state;
if (condition) {
return ;
}
return
Parent
;
}
}
render(
fallback}>
,
scratch
);
expect(scratch.innerHTML).to.eql('');
// this rerender is needed because of Suspense issuing a forceUpdate itself
rerender();
expect(scratch.innerHTML).to.eql('
');
const renderCountAfterSuspend = renderCount;
// Call setState on the suspended component multiple times
suspenderSetState({ count: 1 });
suspenderSetState({ count: 2 });
suspenderSetState({ count: 3 });
rerender();
// Render count should not have increased - setState should not trigger re-renders while suspended
expect(renderCount).to.equal(renderCountAfterSuspend);
expect(scratch.innerHTML).to.equal('
Loading...
');
// Resolve the suspension
resolve();
await promise;
render(
Loading...}>
,
scratch
);
rerender();
// After resolving, the state should have been buffered and applied
expect(scratch.innerHTML).to.equal('
Count: 3
');
});
it('should not schedule renders for forceUpdate on suspended component', () => {
let suspenderForceUpdate;
let renderCount = 0;
class Suspender extends Component {
constructor(props) {
super(props);
suspenderForceUpdate = this.forceUpdate.bind(this);
}
render(props) {
renderCount++;
if (props.suspend && !props.resolved) {
throw props.promise;
}
return
');
const renderCountAfterSuspend = renderCount;
// Call forceUpdate on the suspended component
suspenderForceUpdate();
suspenderForceUpdate();
rerender();
// Render count should not have increased
expect(renderCount).to.equal(renderCountAfterSuspend);
expect(scratch.innerHTML).to.equal('
Loading...
');
});
});
preact-10.29.2/compat/test/browser/svg.test.jsx 0000664 0000000 0000000 00000005564 15202310201 0021367 0 ustar 00root root 0000000 0000000 import React, { createElement } from 'preact/compat';
import {
setupScratch,
teardown,
serializeHtml,
sortAttributes
} from '../../../test/_util/helpers';
describe('svg', () => {
/** @type {HTMLDivElement} */
let scratch;
beforeEach(() => {
scratch = setupScratch();
});
afterEach(() => {
teardown(scratch);
});
it('should render SVG to string', () => {
let svg = (
);
// string -> parse
expect(svg).to.eql(svg);
});
it('should render SVG to DOM #1', () => {
const Demo = () => (
);
React.render(, scratch);
expect(serializeHtml(scratch)).to.equal(
sortAttributes(
''
)
);
});
it('should render SVG to DOM #2', () => {
React.render(
,
scratch
);
expect(serializeHtml(scratch)).to.equal(
sortAttributes(
''
)
);
});
it('should render correct SVG attribute names to the DOM', () => {
React.render(
,
scratch
);
expect(serializeHtml(scratch)).to.eql(
sortAttributes(
''
)
);
});
});
preact-10.29.2/compat/test/browser/testUtils.js 0000664 0000000 0000000 00000001214 15202310201 0021406 0 ustar 00root root 0000000 0000000 /**
* Retrieve a Symbol if supported or use the fallback value
* @param {string} name The name of the Symbol to look up
* @param {number} fallback Fallback value if Symbols are not supported
*/
export function getSymbol(name, fallback) {
let out = fallback;
try {
// eslint-disable-next-line
if (
Function.prototype.toString
.call((0, eval)('Symbol.for'))
.match(/\[native code\]/)
) {
// Concatenate these string literals to prevent the test
// harness and/or Babel from modifying the symbol value.
// eslint-disable-next-line
out = (0, eval)('Sym' + 'bol.for("' + name + '")');
}
} catch (e) {}
return out;
}
preact-10.29.2/compat/test/browser/textarea.test.jsx 0000664 0000000 0000000 00000005033 15202310201 0022374 0 ustar 00root root 0000000 0000000 import React, { render, hydrate, useState } from 'preact/compat';
import ReactDOMServer from 'preact/compat/server';
import { setupScratch, teardown } from '../../../test/_util/helpers';
import { act } from 'preact/test-utils';
describe('Textarea', () => {
/** @type {HTMLElement} */
let scratch;
beforeEach(() => {
scratch = setupScratch();
});
afterEach(() => {
teardown(scratch);
});
it('should alias value to children', () => {
render(
');
hydrate(, scratch);
expect(scratch.firstElementChild.value).to.equal('foo');
// IE11 always displays the value as node.innerHTML
if (!/Trident/.test(window.navigator.userAgent)) {
expect(scratch.innerHTML).to.be.equal('
');
}
});
it('should alias defaultValue to children', () => {
// TODO: IE11 doesn't update `node.value` when
// `node.defaultValue` is set.
if (/Trident/.test(navigator.userAgent)) return;
render(
, scratch);
expect(scratch.firstElementChild.value).to.equal('foo');
});
it('should support resetting the value', () => {
let set;
const App = () => {
const [state, setState] = useState('');
set = setState;
return
');
act(() => {
set('hello');
});
// Note: This looks counterintuitive, but it's working correctly - the value
// missing from HTML because innerHTML doesn't serialize form field values.
// See demo: https://jsfiddle.net/4had2Lu8
// Related renderToString PR: preactjs/preact-render-to-string#161
//
// This is not true for IE11. It displays the value in
// node.innerHTML regardless.
if (!/Trident/.test(window.navigator.userAgent)) {
expect(scratch.innerHTML).to.equal('
');
}
expect(scratch.firstElementChild.value).to.equal('hello');
act(() => {
set('');
});
// Same as earlier: IE11 always displays the value as node.innerHTML
if (!/Trident/.test(window.navigator.userAgent)) {
expect(scratch.innerHTML).to.equal('
');
});
it('handles store updates before subscribing', async () => {
// This test is testing scheduling mechanics, so teardown the manual
// rerender test setup to rely on Preact's built-in scheduling and verify
// this behavior works. We still need a DOM container to render into so set
// that back up.
teardown(scratch);
scratch = setupScratch();
const store = createExternalStore(0);
function App() {
const value = useSyncExternalStore(store.subscribe, store.getState);
useEffect(() => {
Scheduler.log('Passive effect: ' + value);
}, [value]);
return ;
}
const container = document.createElement('div');
const root = createRoot(container);
// Schedule a mutation in the next microtask after the initial render but
// before subscribing to the store
const mutation = defer(() => {
// Assert we are running this mutation before subscribing to the store
expect(store.listeners.size).to.equal(0);
store.set(1);
});
root.render();
expect(container.textContent).to.equal('0');
assertLog([0]);
// Wait for the mutation to occur. Then wait for the passive effects that
// subscribe to the store and log the new value.
await mutation;
await new Promise(r => setTimeout(r, 32));
expect(container.textContent).to.equal('1');
expect(store.listeners.size).to.equal(1);
assertLog(['Passive effect: 0', 1, 'Passive effect: 1']);
});
// The following tests are taken from the React test suite:
// https://github.com/facebook/react/blob/3e09c27b880e1fecdb1eca5db510ecce37ea6be2/packages/use-sync-external-store/src/__tests__/useSyncExternalStoreShared-test.js
describe('React useSyncExternalStore test suite', () => {
it('basic usage', async () => {
const store = createExternalStore('Initial');
function App() {
const text = useSyncExternalStore(store.subscribe, store.getState);
return ;
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() => root.render());
assertLog(['Initial']);
expect(container.textContent).to.equal('Initial');
await act(() => {
store.set('Updated');
});
assertLog(['Updated']);
expect(container.textContent).to.equal('Updated');
});
it('skips re-rendering if nothing changes', async () => {
const store = createExternalStore('Initial');
function App() {
const text = useSyncExternalStore(store.subscribe, store.getState);
return ;
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() => root.render());
assertLog(['Initial']);
expect(container.textContent).to.equal('Initial');
// Update to the same value
await act(() => {
store.set('Initial');
});
// Should not re-render
assertLog([]);
expect(container.textContent).to.equal('Initial');
});
it('switch to a different store', async () => {
const storeA = createExternalStore(0);
const storeB = createExternalStore(0);
let setStore;
function App() {
const [store, _setStore] = useState(storeA);
setStore = _setStore;
const value = useSyncExternalStore(store.subscribe, store.getState);
return ;
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() => root.render());
assertLog([0]);
expect(container.textContent).to.equal('0');
await act(() => {
storeA.set(1);
});
assertLog([1]);
expect(container.textContent).to.equal('1');
// Switch stores and update in the same batch
await act(() => {
// This update will be disregarded
storeA.set(2);
setStore(storeB);
});
// Now reading from B instead of A
assertLog([0]);
expect(container.textContent).to.equal('0');
// Update A
await act(() => {
storeA.set(3);
});
// Nothing happened, because we're no longer subscribed to A
assertLog([]);
expect(container.textContent).to.equal('0');
// Update B
await act(() => {
storeB.set(1);
});
assertLog([1]);
expect(container.textContent).to.equal('1');
});
it('selecting a specific value inside getSnapshot', async () => {
const store = createExternalStore({ a: 0, b: 0 });
function A() {
const a = useSyncExternalStore(
store.subscribe,
() => store.getState().a
);
return ;
}
function B() {
const b = useSyncExternalStore(
store.subscribe,
() => store.getState().b
);
return ;
}
function App() {
return (
);
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() => root.render());
assertLog(['A0', 'B0']);
expect(container.textContent).to.equal('A0B0');
// Update b but not a
await act(() => {
store.set({ a: 0, b: 1 });
});
// Only b re-renders
assertLog(['B1']);
expect(container.textContent).to.equal('A0B1');
// Update a but not b
await act(() => {
store.set({ a: 1, b: 1 });
});
// Only a re-renders
assertLog(['A1']);
expect(container.textContent).to.equal('A1B1');
});
// In React 18, you can't observe in between a sync render and its
// passive effects, so this is only relevant to legacy roots
// @gate enableUseSyncExternalStoreShim
it("compares to current state before bailing out, even when there's a mutation in between the sync and passive effects", async () => {
const store = createExternalStore(0);
function App() {
const value = useSyncExternalStore(store.subscribe, store.getState);
useEffect(() => {
Scheduler.log('Passive effect: ' + value);
}, [value]);
return ;
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() => root.render());
assertLog([0, 'Passive effect: 0']);
// Schedule an update. We'll intentionally not use `act` so that we can
// insert a mutation before React subscribes to the store in a
// passive effect.
store.set(1);
rerender();
assertLog([
1
// Passive effect hasn't fired yet
]);
expect(container.textContent).to.equal('1');
// Flip the store state back to the previous value.
store.set(0);
rerender();
assertLog([
'Passive effect: 1',
// Re-render. If the current state were tracked by updating a ref in a
// passive effect, then this would break because the previous render's
// passive effect hasn't fired yet, so we'd incorrectly think that
// the state hasn't changed.
0
]);
// Should flip back to 0
expect(container.textContent).to.equal('0');
// Preact: Wait for 'Passive effect: 0' to flush from the rAF so it doesn't impact other tests
await new Promise(r => setTimeout(r, 32));
});
it('mutating the store in between render and commit when getSnapshot has changed', async () => {
const store = createExternalStore({ a: 1, b: 1 });
const getSnapshotA = () => store.getState().a;
const getSnapshotB = () => store.getState().b;
function Child1({ step }) {
const value = useSyncExternalStore(store.subscribe, store.getState);
useLayoutEffect(() => {
if (step === 1) {
// Update B in a layout effect. This happens in the same commit
// that changed the getSnapshot in Child2. Child2's effects haven't
// fired yet, so it doesn't have access to the latest getSnapshot. So
// it can't use the getSnapshot to bail out.
Scheduler.log('Update B in commit phase');
store.set({ a: value.a, b: 2 });
}
}, [step]);
return null;
}
function Child2({ step }) {
const label = step === 0 ? 'A' : 'B';
const getSnapshot = step === 0 ? getSnapshotA : getSnapshotB;
const value = useSyncExternalStore(store.subscribe, getSnapshot);
return ;
}
let setStep;
function App() {
const [step, _setStep] = useState(0);
setStep = _setStep;
return (
<>
>
);
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() => root.render());
assertLog(['A1']);
expect(container.textContent).to.equal('A1');
await act(() => {
// Change getSnapshot and update the store in the same batch
setStep(1);
});
assertLog([
'B1',
'Update B in commit phase',
// If Child2 had used the old getSnapshot to bail out, then it would have
// incorrectly bailed out here instead of re-rendering.
'B2'
]);
expect(container.textContent).to.equal('B2');
});
it('mutating the store in between render and commit when getSnapshot has _not_ changed', async () => {
// Same as previous test, but `getSnapshot` does not change
const store = createExternalStore({ a: 1, b: 1 });
const getSnapshotA = () => store.getState().a;
function Child1({ step }) {
const value = useSyncExternalStore(store.subscribe, store.getState);
useLayoutEffect(() => {
if (step === 1) {
// Update B in a layout effect. This happens in the same commit
// that changed the getSnapshot in Child2. Child2's effects haven't
// fired yet, so it doesn't have access to the latest getSnapshot. So
// it can't use the getSnapshot to bail out.
Scheduler.log('Update B in commit phase');
store.set({ a: value.a, b: 2 });
}
}, [step]);
return null;
}
function Child2({ step }) {
const value = useSyncExternalStore(store.subscribe, getSnapshotA);
return ;
}
let setStep;
function App() {
const [step, _setStep] = useState(0);
setStep = _setStep;
return (
<>
>
);
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() => root.render());
assertLog(['A1']);
expect(container.textContent).to.equal('A1');
// This will cause a layout effect, and in the layout effect we'll update
// the store
await act(() => {
setStep(1);
});
assertLog([
'A1',
// This updates B, but since Child2 doesn't subscribe to B, it doesn't
// need to re-render.
'Update B in commit phase'
// No re-render
]);
expect(container.textContent).to.equal('A1');
});
it("does not bail out if the previous update hasn't finished yet", async () => {
const store = createExternalStore(0);
function Child1() {
const value = useSyncExternalStore(store.subscribe, store.getState);
useLayoutEffect(() => {
if (value === 1) {
Scheduler.log('Reset back to 0');
store.set(0);
}
}, [value]);
return ;
}
function Child2() {
const value = useSyncExternalStore(store.subscribe, store.getState);
return ;
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() =>
root.render(
<>
>
)
);
assertLog([0, 0]);
expect(container.textContent).to.equal('00');
await act(() => {
store.set(1);
});
// Preact logs differ from React here cuz of how we do rerendering. We
// rerender subtrees and then commit effects so Child2 never sees the
// update to 1 cuz Child1 rerenders and runs its layout effects first.
assertLog([1, /*1,*/ 'Reset back to 0', 0, 0]);
expect(container.textContent).to.equal('00');
});
it('uses the latest getSnapshot, even if it changed in the same batch as a store update', async () => {
const store = createExternalStore({ a: 0, b: 0 });
const getSnapshotA = () => store.getState().a;
const getSnapshotB = () => store.getState().b;
let setGetSnapshot;
function App() {
const [getSnapshot, _setGetSnapshot] = useState(() => getSnapshotA);
setGetSnapshot = _setGetSnapshot;
const text = useSyncExternalStore(store.subscribe, getSnapshot);
return ;
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() => root.render());
assertLog([0]);
// Update the store and getSnapshot at the same time
await act(() => {
setGetSnapshot(() => getSnapshotB);
store.set({ a: 1, b: 2 });
});
// It should read from B instead of A
assertLog([2]);
expect(container.textContent).to.equal('2');
});
it('handles errors thrown by getSnapshot', async () => {
class ErrorBoundary extends React.Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
render() {
if (this.state.error) {
return ;
}
return this.props.children;
}
}
const store = createExternalStore({
value: 0,
throwInGetSnapshot: false,
throwInIsEqual: false
});
function App() {
const { value } = useSyncExternalStore(store.subscribe, () => {
const state = store.getState();
if (state.throwInGetSnapshot) {
throw new Error('Error in getSnapshot');
}
return state;
});
return ;
}
const errorBoundary = React.createRef();
const container = document.createElement('div');
const root = createRoot(container);
await act(() =>
root.render(
)
);
assertLog([0]);
expect(container.textContent).to.equal('0');
// Update that throws in a getSnapshot. We can catch it with an error boundary.
await act(() => {
store.set({
value: 1,
throwInGetSnapshot: true,
throwInIsEqual: false
});
});
assertLog(['Error in getSnapshot']);
expect(container.textContent).to.equal('Error in getSnapshot');
});
it('getSnapshot can return NaN without infinite loop warning', async () => {
const store = createExternalStore('not a number');
function App() {
const value = useSyncExternalStore(store.subscribe, () =>
parseInt(store.getState(), 10)
);
return ;
}
const container = document.createElement('div');
const root = createRoot(container);
// Initial render that reads a snapshot of NaN. This is OK because we use
// Object.is algorithm to compare values.
await act(() => root.render());
expect(container.textContent).to.equal('NaN');
// Update to real number
await act(() => store.set(123));
expect(container.textContent).to.equal('123');
// Update back to NaN
await act(() => store.set('not a number'));
expect(container.textContent).to.equal('NaN');
});
it('regression test for facebook/react#23150', async () => {
const store = createExternalStore('Initial');
function App() {
const text = useSyncExternalStore(store.subscribe, store.getState);
const [derivedText, setDerivedText] = useState(text);
useEffect(() => {}, []);
if (derivedText !== text.toUpperCase()) {
setDerivedText(text.toUpperCase());
}
return ;
}
const container = document.createElement('div');
const root = createRoot(container);
await act(() => root.render());
assertLog(['INITIAL']);
expect(container.textContent).to.equal('INITIAL');
await act(() => {
store.set('Updated');
});
assertLog(['UPDATED']);
expect(container.textContent).to.equal('UPDATED');
});
});
});
preact-10.29.2/compat/test/ts/ 0000775 0000000 0000000 00000000000 15202310201 0016015 5 ustar 00root root 0000000 0000000 preact-10.29.2/compat/test/ts/forward-ref.tsx 0000664 0000000 0000000 00000001205 15202310201 0020771 0 ustar 00root root 0000000 0000000 import React from '../../src';
const MyInput: React.ForwardFn<{ id: string }, { focus(): void }> = (
props,
ref
) => {
const inputRef = React.useRef(null);
React.useImperativeHandle(ref, () => ({
focus: () => {
if (inputRef.current) {
inputRef.current.focus();
}
}
}));
return ;
};
export const foo = React.forwardRef(MyInput);
export const Bar = React.forwardRef(
(props, ref) => {
return
;
/**
* Have to mock dynamic import as import() throws a syntax error in the test runner
*/
const componentPromise = new Promise<{ default: typeof IsLazyFunctional }>(
resolve => {
setTimeout(() => {
resolve({ default: IsLazyFunctional });
}, 800);
}
);
/**
* For usage with import:
* const IsLazyComp = lazy(() => import('./lazy'));
*/
const IsLazyFunc = React.lazy(() => componentPromise);
// Suspense using lazy component
class ReactSuspensefulFunc extends React.Component {
render() {
return (
}>
);
}
}
//SuspenseList using lazy components
function ReactSuspenseListTester(_props: any) {
return (
}>
}>
);
}
const Comp = () =>
Hello world
;
const importComponent = async () => {
return { MyComponent: Comp };
};
const Lazy = React.lazy(() =>
importComponent().then(mod => ({ default: mod.MyComponent }))
);
// eslint-disable-next-line
function App() {
return ;
}
preact-10.29.2/compat/test/ts/tsconfig.json 0000664 0000000 0000000 00000000603 15202310201 0020523 0 ustar 00root root 0000000 0000000 {
"compilerOptions": {
"target": "es6",
"module": "es6",
"moduleResolution": "node",
"lib": ["es6", "dom"],
"strict": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"noEmit": true,
"allowSyntheticDefaultImports": true,
"paths": {
"preact": ["../../../src/index.d.ts"]
}
},
"include": ["./**/*.ts", "./**/*.tsx"]
}
preact-10.29.2/compat/test/ts/utils.ts 0000664 0000000 0000000 00000000157 15202310201 0017530 0 ustar 00root root 0000000 0000000 /**
* Assert the parameter is of a specific type.
*/
export const expectType = (_: T): void => undefined;
preact-10.29.2/config/ 0000775 0000000 0000000 00000000000 15202310201 0014372 5 ustar 00root root 0000000 0000000 preact-10.29.2/config/codemod-const.js 0000664 0000000 0000000 00000002255 15202310201 0017472 0 ustar 00root root 0000000 0000000 /* eslint no-console:0 */
/** Find constants (identified by ALL_CAPS_DECLARATIONS), and inline them globally.
* This is safe because Preact *only* uses global constants.
*/
export default (file, api) => {
let j = api.jscodeshift,
code = j(file.source),
constants = {},
found = 0;
code
.find(j.VariableDeclaration)
.filter(decl => {
for (let i = decl.value.declarations.length; i--; ) {
let node = decl.value.declarations[i],
name = node.id && node.id.name,
init = node.init;
if (name && init && name.match(/^[A-Z0-9_$]+$/g) && !init.regex) {
if (init.type === 'Literal') {
// console.log(`Inlining constant: ${name}=${init.raw}`);
found++;
constants[name] = init;
// remove declaration
decl.value.declarations.splice(i, 1);
// if it's the last, we'll remove the whole statement
return !decl.value.declarations.length;
}
}
}
return false;
})
.remove();
code
.find(j.Identifier)
.filter(
path => path.value.name && constants.hasOwnProperty(path.value.name)
)
.replaceWith(path => (found++, constants[path.value.name]));
return found ? code.toSource({ quote: 'single' }) : null;
};
preact-10.29.2/config/codemod-let-name.js 0000664 0000000 0000000 00000000701 15202310201 0020040 0 ustar 00root root 0000000 0000000 /**
* Restores var names transformed by babel's let block scoping
*/
export default (file, api) => {
let j = api.jscodeshift;
let code = j(file.source);
// @TODO unsafe, but without it we gain 20b gzipped: https://www.diffchecker.com/bVrOJWTO
code
.findVariableDeclarators()
.filter(d => /^_i/.test(d.value.id.name))
.renameTo('i');
code.findVariableDeclarators('_key').renameTo('key');
return code.toSource({ quote: 'single' });
};
preact-10.29.2/config/codemod-strip-tdz.js 0000664 0000000 0000000 00000002572 15202310201 0020306 0 ustar 00root root 0000000 0000000 /* eslint no-console:0 */
// parent node types that we don't want to remove pointless initializations from (because it breaks hoisting)
const BLOCKED = ['ForStatement', 'WhileStatement']; // 'IfStatement', 'SwitchStatement'
/** Removes var initialization to `void 0`, which Babel adds for TDZ strictness. */
export default (file, api) => {
let { jscodeshift } = api,
found = 0;
let code = jscodeshift(file.source)
.find(jscodeshift.VariableDeclaration)
.forEach(handleDeclaration);
function handleDeclaration(decl) {
let p = decl,
remove = true;
while ((p = p.parentPath)) {
if (~BLOCKED.indexOf(p.value.type)) {
remove = false;
break;
}
}
decl.value.declarations.filter(isPointless).forEach(node => {
if (remove === false) {
console.log(
`> Skipping removal of undefined init for "${node.id.name}": within ${p.value.type}`
);
} else {
removeNodeInitialization(node);
}
});
}
function removeNodeInitialization(node) {
node.init = null;
found++;
}
function isPointless(node) {
let { init } = node;
if (init) {
if (
init.type === 'UnaryExpression' &&
init.operator === 'void' &&
init.argument.value == 0
) {
return true;
}
if (init.type === 'Identifier' && init.name === 'undefined') {
return true;
}
}
return false;
}
return found ? code.toSource({ quote: 'single' }) : null;
};
preact-10.29.2/config/compat-entries.js 0000664 0000000 0000000 00000001175 15202310201 0017666 0 ustar 00root root 0000000 0000000 const path = require('path');
const fs = require('fs');
const kl = require('kolorist');
const pkgFiles = new Set(require('../package.json').files);
const compatDir = path.join(__dirname, '..', 'compat');
const files = fs.readdirSync(compatDir);
let missing = 0;
for (const file of files) {
const expected = 'compat/' + file;
if (/\.(js|mjs)$/.test(file) && !pkgFiles.has(expected)) {
missing++;
const filePath = kl.cyan('compat/' + file);
const label = kl.inverse(kl.red(' ERROR '));
console.error(
`${label} File ${filePath} is missing in "files" entry in package.json`
);
}
}
if (missing > 0) {
process.exit(1);
}
preact-10.29.2/config/node-13-exports.js 0000664 0000000 0000000 00000001423 15202310201 0017600 0 ustar 00root root 0000000 0000000 const fs = require('fs');
const subRepositories = [
'compat',
'debug',
'devtools',
'hooks',
'jsx-runtime',
'test-utils'
];
const snakeCaseToCamelCase = str =>
str.replace(/([-_][a-z])/g, group => group.toUpperCase().replace('-', ''));
const copyPreact = () => {
// Copy .module.js --> .mjs for Node 13 compat.
fs.writeFileSync(
`${process.cwd()}/dist/preact.mjs`,
fs.readFileSync(`${process.cwd()}/dist/preact.module.js`)
);
};
const copy = name => {
// Copy .module.js --> .mjs for Node 13 compat.
const filename = name.includes('-') ? snakeCaseToCamelCase(name) : name;
fs.writeFileSync(
`${process.cwd()}/${name}/dist/${filename}.mjs`,
fs.readFileSync(`${process.cwd()}/${name}/dist/${filename}.module.js`)
);
};
copyPreact();
subRepositories.forEach(copy);
preact-10.29.2/debug/ 0000775 0000000 0000000 00000000000 15202310201 0014213 5 ustar 00root root 0000000 0000000 preact-10.29.2/debug/LICENSE 0000664 0000000 0000000 00000002077 15202310201 0015226 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2015-present Jason Miller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
preact-10.29.2/debug/mangle.json 0000664 0000000 0000000 00000001254 15202310201 0016353 0 ustar 00root root 0000000 0000000 {
"help": {
"what is this file?": "It controls protected/private property mangling so that minified builds have consistent property names.",
"why are there duplicate minified properties?": "Most properties are only used on one type of objects, so they can have the same name since they will never collide. Doing this reduces size."
},
"minify": {
"mangle": {
"properties": {
"regex": "^_[^_]",
"reserved": [
"__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
"__REACT_DEVTOOLS_GLOBAL_HOOK__",
"__PREACT_DEVTOOLS__",
"_renderers",
"__source",
"__self"
]
}
}
}
}
preact-10.29.2/debug/package.json 0000664 0000000 0000000 00000001160 15202310201 0016477 0 ustar 00root root 0000000 0000000 {
"name": "preact-debug",
"amdName": "preactDebug",
"version": "1.0.0",
"private": true,
"description": "Preact extensions for development",
"main": "dist/debug.js",
"module": "dist/debug.module.js",
"umd:main": "dist/debug.umd.js",
"source": "src/index.js",
"license": "MIT",
"mangle": {
"regex": "^(?!_renderer)^_"
},
"peerDependencies": {
"preact": "^10.0.0"
},
"exports": {
".": {
"types": "./src/index.d.ts",
"browser": "./dist/debug.module.js",
"umd": "./dist/debug.umd.js",
"import": "./dist/debug.mjs",
"require": "./dist/debug.js"
}
}
}
preact-10.29.2/debug/src/ 0000775 0000000 0000000 00000000000 15202310201 0015002 5 ustar 00root root 0000000 0000000 preact-10.29.2/debug/src/check-props.js 0000664 0000000 0000000 00000002533 15202310201 0017561 0 ustar 00root root 0000000 0000000 const ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
let loggedTypeFailures = {};
/**
* Reset the history of which prop type warnings have been logged.
*/
export function resetPropWarnings() {
loggedTypeFailures = {};
}
/**
* Assert that the values match with the type specs.
* Error messages are memorized and will only be shown once.
*
* Adapted from https://github.com/facebook/prop-types/blob/master/checkPropTypes.js
*
* @param {object} typeSpecs Map of name to a ReactPropType
* @param {object} values Runtime values that need to be type-checked
* @param {string} location e.g. "prop", "context", "child context"
* @param {string} componentName Name of the component for error messages.
* @param {?Function} getStack Returns the component stack.
*/
export function checkPropTypes(
typeSpecs,
values,
location,
componentName,
getStack
) {
Object.keys(typeSpecs).forEach(typeSpecName => {
let error;
try {
error = typeSpecs[typeSpecName](
values,
typeSpecName,
componentName,
location,
null,
ReactPropTypesSecret
);
} catch (e) {
error = e;
}
if (error && !(error.message in loggedTypeFailures)) {
loggedTypeFailures[error.message] = true;
console.error(
`Failed ${location} type: ${error.message}${
(getStack && `\n${getStack()}`) || ''
}`
);
}
});
}
preact-10.29.2/debug/src/component-stack.js 0000664 0000000 0000000 00000007451 15202310201 0020454 0 ustar 00root root 0000000 0000000 import { options, Fragment } from 'preact';
/**
* Get human readable name of the component/dom node
* @param {import('./internal').VNode} vnode
* @param {import('./internal').VNode} vnode
* @returns {string}
*/
export function getDisplayName(vnode) {
if (vnode.type === Fragment) {
return 'Fragment';
} else if (typeof vnode.type == 'function') {
return vnode.type.displayName || vnode.type.name;
} else if (typeof vnode.type == 'string') {
return vnode.type;
}
return '#text';
}
/**
* Used to keep track of the currently rendered `vnode` and print it
* in debug messages.
*/
let renderStack = [];
/**
* Keep track of the current owners. An owner describes a component
* which was responsible to render a specific `vnode`. This exclude
* children that are passed via `props.children`, because they belong
* to the parent owner.
*
* ```jsx
* const Foo = props =>
{props.children}
// div's owner is Foo
* const Bar = props => {
* return (
* // Foo's owner is Bar, span's owner is Bar
* )
* }
* ```
*
* Note: A `vnode` may be hoisted to the root scope due to compiler
* optimiztions. In these cases the `_owner` will be different.
*/
let ownerStack = [];
/**
* Get the currently rendered `vnode`
* @returns {import('./internal').VNode | null}
*/
export function getCurrentVNode() {
return renderStack.length > 0 ? renderStack[renderStack.length - 1] : null;
}
/**
* If the user doesn't have `@babel/plugin-transform-react-jsx-source`
* somewhere in his tool chain we can't print the filename and source
* location of a component. In that case we just omit that, but we'll
* print a helpful message to the console, notifying the user of it.
*/
let showJsxSourcePluginWarning = true;
/**
* Check if a `vnode` is a possible owner.
* @param {import('./internal').VNode} vnode
*/
function isPossibleOwner(vnode) {
return typeof vnode.type == 'function' && vnode.type != Fragment;
}
/**
* Return the component stack that was captured up to this point.
* @param {import('./internal').VNode} vnode
* @returns {string}
*/
export function getOwnerStack(vnode) {
const stack = [vnode];
let next = vnode;
while (next._owner != null) {
stack.push(next._owner);
next = next._owner;
}
return stack.reduce((acc, owner) => {
acc += ` in ${getDisplayName(owner)}`;
const source = owner.__source;
if (source) {
acc += ` (at ${source.fileName}:${source.lineNumber})`;
} else if (showJsxSourcePluginWarning) {
console.warn(
'Add @babel/plugin-transform-react-jsx-source to get a more detailed component stack. Note that you should not add it to production builds of your App for bundle size reasons.'
);
}
showJsxSourcePluginWarning = false;
return (acc += '\n');
}, '');
}
/**
* Setup code to capture the component trace while rendering. Note that
* we cannot simply traverse `vnode._parent` upwards, because we have some
* debug messages for `this.setState` where the `vnode` is `undefined`.
*/
export function setupComponentStack() {
let oldDiff = options._diff;
let oldDiffed = options.diffed;
let oldRoot = options._root;
let oldVNode = options.vnode;
let oldRender = options._render;
options.diffed = vnode => {
if (isPossibleOwner(vnode)) {
ownerStack.pop();
}
renderStack.pop();
if (oldDiffed) oldDiffed(vnode);
};
options._diff = vnode => {
if (isPossibleOwner(vnode)) {
renderStack.push(vnode);
}
if (oldDiff) oldDiff(vnode);
};
options._root = (vnode, parent) => {
ownerStack = [];
if (oldRoot) oldRoot(vnode, parent);
};
options.vnode = vnode => {
vnode._owner =
ownerStack.length > 0 ? ownerStack[ownerStack.length - 1] : null;
if (oldVNode) oldVNode(vnode);
};
options._render = vnode => {
if (isPossibleOwner(vnode)) {
ownerStack.push(vnode);
}
if (oldRender) oldRender(vnode);
};
}
preact-10.29.2/debug/src/constants.js 0000664 0000000 0000000 00000000151 15202310201 0017351 0 ustar 00root root 0000000 0000000 export const ELEMENT_NODE = 1;
export const DOCUMENT_NODE = 9;
export const DOCUMENT_FRAGMENT_NODE = 11;
preact-10.29.2/debug/src/debug.js 0000664 0000000 0000000 00000041747 15202310201 0016443 0 ustar 00root root 0000000 0000000 import { checkPropTypes } from './check-props';
import { options, Component } from 'preact';
import {
ELEMENT_NODE,
DOCUMENT_NODE,
DOCUMENT_FRAGMENT_NODE
} from './constants';
import {
getOwnerStack,
setupComponentStack,
getCurrentVNode,
getDisplayName
} from './component-stack';
import { assign, isNaN } from './util';
const isWeakMapSupported = typeof WeakMap == 'function';
/**
* @param {import('./internal').VNode} vnode
* @returns {Array}
*/
function getDomChildren(vnode) {
let domChildren = [];
if (!vnode._children) return domChildren;
vnode._children.forEach(child => {
if (child && typeof child.type === 'function') {
domChildren.push.apply(domChildren, getDomChildren(child));
} else if (child && typeof child.type === 'string') {
domChildren.push(child.type);
}
});
return domChildren;
}
/**
* @param {import('./internal').VNode} parent
* @returns {string}
*/
function getClosestDomNodeParentName(parent) {
if (!parent) return '';
if (typeof parent.type == 'function') {
if (parent._parent == null) {
if (parent._dom != null && parent._dom.parentNode != null) {
return parent._dom.parentNode.localName;
}
return '';
}
return getClosestDomNodeParentName(parent._parent);
}
return /** @type {string} */ (parent.type);
}
export function initDebug() {
setupComponentStack();
let hooksAllowed = false;
/* eslint-disable no-console */
let oldBeforeDiff = options._diff;
let oldDiffed = options.diffed;
let oldVnode = options.vnode;
let oldRender = options._render;
let oldCatchError = options._catchError;
let oldRoot = options._root;
let oldHook = options._hook;
const warnedComponents = !isWeakMapSupported
? null
: {
useEffect: new WeakMap(),
useLayoutEffect: new WeakMap(),
lazyPropTypes: new WeakMap()
};
const deprecations = [];
options._catchError = (error, vnode, oldVNode, errorInfo) => {
let component = vnode && vnode._component;
if (component && typeof error.then == 'function') {
const promise = error;
error = new Error(
`Missing Suspense. The throwing component was: ${getDisplayName(vnode)}`
);
let parent = vnode;
for (; parent; parent = parent._parent) {
if (parent._component && parent._component._childDidSuspend) {
error = promise;
break;
}
}
// We haven't recovered and we know at this point that there is no
// Suspense component higher up in the tree
if (error instanceof Error) {
throw error;
}
}
try {
errorInfo = errorInfo || {};
errorInfo.componentStack = getOwnerStack(vnode);
oldCatchError(error, vnode, oldVNode, errorInfo);
// when an error was handled by an ErrorBoundary we will nonetheless emit an error
// event on the window object. This is to make up for react compatibility in dev mode
// and thus make the Next.js dev overlay work.
if (typeof error.then != 'function') {
setTimeout(() => {
throw error;
});
}
} catch (e) {
throw e;
}
};
options._root = (vnode, parentNode) => {
if (!parentNode) {
throw new Error(
'Undefined parent passed to render(), this is the second argument.\n' +
'Check if the element is available in the DOM/has the correct id.'
);
}
let isValid;
switch (parentNode.nodeType) {
case ELEMENT_NODE:
case DOCUMENT_FRAGMENT_NODE:
case DOCUMENT_NODE:
isValid = true;
break;
default:
isValid = false;
}
if (!isValid) {
let componentName = getDisplayName(vnode);
throw new Error(
`Expected a valid HTML node as a second argument to render. Received ${parentNode} instead: render(<${componentName} />, ${parentNode});`
);
}
if (oldRoot) oldRoot(vnode, parentNode);
};
options._diff = vnode => {
let { type } = vnode;
hooksAllowed = true;
if (type === undefined) {
throw new Error(
'Undefined component passed to createElement()\n\n' +
'You likely forgot to export your component or might have mixed up default and named imports' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
} else if (type != null && typeof type == 'object') {
if (type._children !== undefined && type._dom !== undefined) {
throw new Error(
`Invalid type passed to createElement(): ${type}\n\n` +
'Did you accidentally pass a JSX literal as JSX twice?\n\n' +
` let My${getDisplayName(vnode)} = ${serializeVNode(type)};\n` +
` let vnode = ;\n\n` +
'This usually happens when you export a JSX literal and not the component.' +
`\n\n${getOwnerStack(vnode)}`
);
}
throw new Error(
'Invalid type passed to createElement(): ' +
(Array.isArray(type) ? 'array' : type)
);
}
if (
vnode.ref !== undefined &&
typeof vnode.ref != 'function' &&
typeof vnode.ref != 'object' &&
!('$$typeof' in vnode) // allow string refs when preact-compat is installed
) {
throw new Error(
`Component's "ref" property should be a function, or an object created ` +
`by createRef(), but got [${typeof vnode.ref}] instead\n` +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
}
if (typeof vnode.type == 'string') {
for (const key in vnode.props) {
if (
key[0] === 'o' &&
key[1] === 'n' &&
typeof vnode.props[key] != 'function' &&
vnode.props[key] != null
) {
throw new Error(
`Component's "${key}" property should be a function, ` +
`but got [${typeof vnode.props[key]}] instead\n` +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
}
}
}
// Check prop-types if available
if (typeof vnode.type == 'function' && vnode.type.propTypes) {
if (
vnode.type.displayName === 'Lazy' &&
warnedComponents &&
!warnedComponents.lazyPropTypes.has(vnode.type)
) {
const m =
'PropTypes are not supported on lazy(). Use propTypes on the wrapped component itself. ';
try {
const lazyVNode = vnode.type();
warnedComponents.lazyPropTypes.set(vnode.type, true);
console.warn(
m + `Component wrapped in lazy() is ${getDisplayName(lazyVNode)}`
);
} catch (promise) {
console.warn(
m + "We will log the wrapped component's name once it is loaded."
);
}
}
let values = vnode.props;
if (vnode.type._forwarded) {
values = assign({}, values);
delete values.ref;
}
checkPropTypes(
vnode.type.propTypes,
values,
'prop',
getDisplayName(vnode),
() => getOwnerStack(vnode)
);
}
if (oldBeforeDiff) oldBeforeDiff(vnode);
};
let renderCount = 0;
let currentComponent;
options._render = vnode => {
if (oldRender) {
oldRender(vnode);
}
hooksAllowed = true;
const nextComponent = vnode._component;
if (nextComponent === currentComponent) {
renderCount++;
} else {
renderCount = 1;
}
if (renderCount >= 25) {
throw new Error(
`Too many re-renders. This is limited to prevent an infinite loop ` +
`which may lock up your browser. The component causing this is: ${getDisplayName(
vnode
)}`
);
}
currentComponent = nextComponent;
};
options._hook = (comp, index, type) => {
if (!comp || !hooksAllowed) {
throw new Error('Hook can only be invoked from render methods.');
}
if (oldHook) oldHook(comp, index, type);
};
// Ideally we'd want to print a warning once per component, but we
// don't have access to the vnode that triggered it here. As a
// compromise and to avoid flooding the console with warnings we
// print each deprecation warning only once.
const warn = (property, message) => ({
get() {
const key = 'get' + property + message;
if (deprecations && deprecations.indexOf(key) < 0) {
deprecations.push(key);
console.warn(`getting vnode.${property} is deprecated, ${message}`);
}
},
set() {
const key = 'set' + property + message;
if (deprecations && deprecations.indexOf(key) < 0) {
deprecations.push(key);
console.warn(`setting vnode.${property} is not allowed, ${message}`);
}
}
});
const deprecatedAttributes = {
nodeName: warn('nodeName', 'use vnode.type'),
attributes: warn('attributes', 'use vnode.props'),
children: warn('children', 'use vnode.props.children')
};
const deprecatedProto = Object.create({}, deprecatedAttributes);
options.vnode = vnode => {
const props = vnode.props;
if (
vnode.type !== null &&
props != null &&
('__source' in props || '__self' in props)
) {
const newProps = (vnode.props = {});
for (let i in props) {
const v = props[i];
if (i === '__source') vnode.__source = v;
else if (i === '__self') vnode.__self = v;
else newProps[i] = v;
}
}
// eslint-disable-next-line
vnode.__proto__ = deprecatedProto;
if (oldVnode) oldVnode(vnode);
};
options.diffed = vnode => {
const { type, _parent: parent } = vnode;
// Check if the user passed plain objects as children. Note that we cannot
// move this check into `options.vnode` because components can receive
// children in any shape they want (e.g.
// `{{ foo: 123, bar: "abc" }}`).
// Putting this check in `options.diffed` ensures that
// `vnode._children` is set and that we only validate the children
// that were actually rendered.
if (vnode._children) {
vnode._children.forEach(child => {
if (typeof child === 'object' && child && child.type === undefined) {
const keys = Object.keys(child).join(',');
throw new Error(
`Objects are not valid as a child. Encountered an object with the keys {${keys}}.` +
`\n\n${getOwnerStack(vnode)}`
);
}
});
}
if (vnode._component === currentComponent) {
renderCount = 0;
}
if (
typeof type === 'string' &&
(isTableElement(type) ||
type === 'p' ||
type === 'a' ||
type === 'button')
) {
// Avoid false positives when Preact only partially rendered the
// HTML tree. Whilst we attempt to include the outer DOM in our
// validation, this wouldn't work on the server for
// `preact-render-to-string`. There we'd otherwise flood the terminal
// with false positives, which we'd like to avoid.
let domParentName = getClosestDomNodeParentName(parent);
if (domParentName !== '' && isTableElement(type)) {
if (
type === 'table' &&
// Tables can be nested inside each other if it's inside a cell.
// See https://developer.mozilla.org/en-US/docs/Learn/HTML/Tables/Advanced#nesting_tables
domParentName !== 'td' &&
isTableElement(domParentName)
) {
console.error(
'Improper nesting of table. Your
should not have a table-node parent.' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
} else if (
(type === 'thead' || type === 'tfoot' || type === 'tbody') &&
domParentName !== 'table'
) {
console.error(
'Improper nesting of table. Your should have a
parent.' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
} else if (
type === 'tr' &&
domParentName !== 'thead' &&
domParentName !== 'tfoot' &&
domParentName !== 'tbody'
) {
console.error(
'Improper nesting of table. Your
should have a parent.' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
} else if (type === 'td' && domParentName !== 'tr') {
console.error(
'Improper nesting of table. Your
should have a
parent.' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
} else if (type === 'th' && domParentName !== 'tr') {
console.error(
'Improper nesting of table. Your
should have a
.' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
}
} else if (type === 'p') {
let illegalDomChildrenTypes = getDomChildren(vnode).filter(childType =>
ILLEGAL_PARAGRAPH_CHILD_ELEMENTS.test(childType)
);
if (illegalDomChildrenTypes.length) {
console.error(
'Improper nesting of paragraph. Your
should not have ' +
illegalDomChildrenTypes.join(', ') +
' as child-elements.' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
}
} else if (type === 'a' || type === 'button') {
if (getDomChildren(vnode).indexOf(type) !== -1) {
console.error(
`Improper nesting of interactive content. Your <${type}>` +
` should not have other ${type === 'a' ? 'anchor' : 'button'}` +
' tags as child-elements.' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
}
}
}
hooksAllowed = false;
if (oldDiffed) oldDiffed(vnode);
if (vnode._children != null) {
const keys = [];
for (let i = 0; i < vnode._children.length; i++) {
const child = vnode._children[i];
if (!child || child.key == null) continue;
const key = child.key;
if (keys.indexOf(key) !== -1) {
console.error(
'Following component has two or more children with the ' +
`same key attribute: "${key}". This may cause glitches and misbehavior ` +
'in rendering process. Component: \n\n' +
serializeVNode(vnode) +
`\n\n${getOwnerStack(vnode)}`
);
// Break early to not spam the console
break;
}
keys.push(key);
}
}
if (vnode._component != null && vnode._component.__hooks != null) {
// Validate that none of the hooks in this component contain arguments that are NaN.
// This is a common mistake that can be hard to debug, so we want to catch it early.
const hooks = vnode._component.__hooks._list;
if (hooks) {
for (let i = 0; i < hooks.length; i += 1) {
const hook = hooks[i];
if (hook._args) {
for (let j = 0; j < hook._args.length; j++) {
const arg = hook._args[j];
if (isNaN(arg)) {
const componentName = getDisplayName(vnode);
console.warn(
`Invalid argument passed to hook. Hooks should not be called with NaN in the dependency array. Hook index ${i} in component ${componentName} was called with NaN.`
);
}
}
}
}
}
}
};
}
const setState = Component.prototype.setState;
Component.prototype.setState = function (update, callback) {
if (this._vnode == null) {
// `this._vnode` will be `null` during componentWillMount. But it
// is perfectly valid to call `setState` during cWM. So we
// need an additional check to verify that we are dealing with a
// call inside constructor.
if (this.state == null) {
console.warn(
`Calling "this.setState" inside the constructor of a component is a ` +
`no-op and might be a bug in your application. Instead, set ` +
`"this.state = {}" directly.\n\n${getOwnerStack(getCurrentVNode())}`
);
}
}
return setState.call(this, update, callback);
};
function isTableElement(type) {
return (
type === 'table' ||
type === 'tfoot' ||
type === 'tbody' ||
type === 'thead' ||
type === 'td' ||
type === 'tr' ||
type === 'th'
);
}
const ILLEGAL_PARAGRAPH_CHILD_ELEMENTS =
/^(address|article|aside|blockquote|details|div|dl|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|main|menu|nav|ol|p|pre|search|section|table|ul)$/;
const forceUpdate = Component.prototype.forceUpdate;
Component.prototype.forceUpdate = function (callback) {
if (this._vnode == null) {
console.warn(
`Calling "this.forceUpdate" inside the constructor of a component is a ` +
`no-op and might be a bug in your application.\n\n${getOwnerStack(
getCurrentVNode()
)}`
);
} else if (this._parentDom == null) {
console.warn(
`Can't call "this.forceUpdate" on an unmounted component. This is a no-op, ` +
`but it indicates a memory leak in your application. To fix, cancel all ` +
`subscriptions and asynchronous tasks in the componentWillUnmount method.` +
`\n\n${getOwnerStack(this._vnode)}`
);
}
return forceUpdate.call(this, callback);
};
/**
* Serialize a vnode tree to a string
* @param {import('./internal').VNode} vnode
* @returns {string}
*/
export function serializeVNode(vnode) {
let { props } = vnode;
let name = getDisplayName(vnode);
let attrs = '';
for (let prop in props) {
if (props.hasOwnProperty(prop) && prop !== 'children') {
let value = props[prop];
// If it is an object but doesn't have toString(), use Object.toString
if (typeof value == 'function') {
value = `function ${value.displayName || value.name}() {}`;
}
value =
Object(value) === value && !value.toString
? Object.prototype.toString.call(value)
: value + '';
attrs += ` ${prop}=${JSON.stringify(value)}`;
}
}
let children = props.children;
return `<${name}${attrs}${
children && children.length ? '>..' + name + '>' : ' />'
}`;
}
options._hydrationMismatch = (newVNode, excessDomChildren) => {
const { type } = newVNode;
const availableTypes = excessDomChildren
.map(child => child && child.localName)
.filter(Boolean);
console.error(
`Expected a DOM node of type "${type}" but found "${availableTypes.join(', ')}" as available DOM-node(s), this is caused by the SSR'd HTML containing different DOM-nodes compared to the hydrated one.\n\n${getOwnerStack(newVNode)}`
);
};
preact-10.29.2/debug/src/index.d.ts 0000664 0000000 0000000 00000001210 15202310201 0016675 0 ustar 00root root 0000000 0000000 import { VNode } from 'preact';
/**
* Get the currently rendered `vnode`
*/
export function getCurrentVNode(): VNode | null;
/**
* Return the component stack that was captured up to this point.
*/
export function getOwnerStack(vnode: VNode): string;
/**
* Setup code to capture the component trace while rendering. Note that
* we cannot simply traverse `vnode._parent` upwards, because we have some
* debug messages for `this.setState` where the `vnode` is `undefined`.
*/
export function setupComponentStack(): void;
/**
* Reset the history of which prop type warnings have been logged.
*/
export function resetPropWarnings(): void;
preact-10.29.2/debug/src/index.js 0000664 0000000 0000000 00000000331 15202310201 0016444 0 ustar 00root root 0000000 0000000 import { initDebug } from './debug';
import 'preact/devtools';
initDebug();
export { resetPropWarnings } from './check-props';
export {
getCurrentVNode,
getDisplayName,
getOwnerStack
} from './component-stack';
preact-10.29.2/debug/src/internal.d.ts 0000664 0000000 0000000 00000004376 15202310201 0017422 0 ustar 00root root 0000000 0000000 import { Component, PreactElement, VNode, Options } from '../../src/internal';
export { Component, PreactElement, VNode, Options };
export interface DevtoolsInjectOptions {
/** 1 = DEV, 0 = production */
bundleType: 1 | 0;
/** The devtools enable different features for different versions of react */
version: string;
/** Informative string, currently unused in the devtools */
rendererPackageName: string;
/** Find the root dom node of a vnode */
findHostInstanceByFiber(vnode: VNode): HTMLElement | null;
/** Find the closest vnode given a dom node */
findFiberByHostInstance(instance: HTMLElement): VNode | null;
}
export interface DevtoolsUpdater {
setState(objOrFn: any): void;
forceUpdate(): void;
setInState(path: Array, value: any): void;
setInProps(path: Array, value: any): void;
setInContext(): void;
}
export type NodeType = 'Composite' | 'Native' | 'Wrapper' | 'Text';
export interface DevtoolData {
nodeType: NodeType;
// Component type
type: any;
name: string;
ref: any;
key: string | number;
updater: DevtoolsUpdater | null;
text: string | number | null;
state: any;
props: any;
children: VNode[] | string | number | null;
publicInstance: PreactElement | Text | Component;
memoizedInteractions: any[];
actualDuration: number;
actualStartTime: number;
treeBaseDuration: number;
}
export type EventType =
| 'unmount'
| 'rootCommitted'
| 'root'
| 'mount'
| 'update'
| 'updateProfileTimes';
export interface DevtoolsEvent {
data?: DevtoolData;
internalInstance: VNode;
renderer: string;
type: EventType;
}
export interface DevtoolsHook {
_renderers: Record;
_roots: Set;
on(ev: string, listener: () => void): void;
emit(ev: string, data?: object): void;
helpers: Record;
getFiberRoots(rendererId: string): Set;
inject(config: DevtoolsInjectOptions): string;
onCommitFiberRoot(rendererId: string, root: VNode): void;
onCommitFiberUnmount(rendererId: string, vnode: VNode): void;
}
export interface DevtoolsWindow extends Window {
/**
* If the devtools extension is installed it will inject this object into
* the dom. This hook handles all communications between preact and the
* devtools panel.
*/
__REACT_DEVTOOLS_GLOBAL_HOOK__?: DevtoolsHook;
}
preact-10.29.2/debug/src/util.js 0000664 0000000 0000000 00000000612 15202310201 0016314 0 ustar 00root root 0000000 0000000 /**
* Assign properties from `props` to `obj`
* @template O, P The obj and props types
* @param {O} obj The object to copy properties to
* @param {P} props The object to copy properties from
* @returns {O & P}
*/
export function assign(obj, props) {
for (let i in props) obj[i] = props[i];
return /** @type {O & P} */ (obj);
}
export function isNaN(value) {
return value !== value;
}
preact-10.29.2/debug/test/ 0000775 0000000 0000000 00000000000 15202310201 0015172 5 ustar 00root root 0000000 0000000 preact-10.29.2/debug/test/browser/ 0000775 0000000 0000000 00000000000 15202310201 0016655 5 ustar 00root root 0000000 0000000 preact-10.29.2/debug/test/browser/component-stack-2.test.jsx 0000664 0000000 0000000 00000002274 15202310201 0023632 0 ustar 00root root 0000000 0000000 import { createElement, render, Component } from 'preact';
import 'preact/debug';
import { setupScratch, teardown } from '../../../test/_util/helpers';
/** @jsx createElement */
// This test is not part of component-stack.test.js to avoid it being
// transpiled with '@babel/plugin-transform-react-jsx-source' enabled.
describe('component stack', () => {
/** @type {HTMLDivElement} */
let scratch;
let errors = [];
let warnings = [];
beforeEach(() => {
scratch = setupScratch();
errors = [];
warnings = [];
sinon.stub(console, 'error').callsFake(e => errors.push(e));
sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
});
afterEach(() => {
console.error.restore();
console.warn.restore();
teardown(scratch);
});
it('should print a warning when "@babel/plugin-transform-react-jsx-source" is not installed', () => {
function Foo() {
return ;
}
class Thrower extends Component {
constructor(props) {
super(props);
this.setState({ foo: 1 });
}
render() {
return
;
}
}
render(, scratch);
// This has a JSX transform warning, so we need to remove it
warnings.shift();
let lines = getStack(warnings).split('\n');
expect(lines[0].indexOf('Thrower') > -1).to.equal(true);
expect(lines[1].indexOf('Foo') > -1).to.equal(true);
});
it('should only print owners', () => {
function Foo(props) {
return
{props.children}
;
}
function Bar() {
return (
);
}
class Thrower extends Component {
render() {
return (
foo
);
}
}
render(, scratch);
let lines = getStack(errors).split('\n');
expect(lines[0].indexOf('tr') > -1).to.equal(true);
expect(lines[1].indexOf('Thrower') > -1).to.equal(true);
expect(lines[2].indexOf('Bar') > -1).to.equal(true);
});
it('should not print a warning when "@babel/plugin-transform-react-jsx-source" is installed', () => {
function Thrower() {
throw new Error('foo');
}
try {
render(, scratch);
} catch {}
expect(warnings.join(' ')).to.not.include(
'@babel/plugin-transform-react-jsx-source'
);
});
});
preact-10.29.2/debug/test/browser/debug-compat.test.jsx 0000664 0000000 0000000 00000003720 15202310201 0022732 0 ustar 00root root 0000000 0000000 import { createElement, render, createRef } from 'preact';
import { setupScratch, teardown } from '../../../test/_util/helpers';
import './fakeDevTools';
import 'preact/debug';
import * as PropTypes from 'prop-types';
// eslint-disable-next-line no-duplicate-imports
import { resetPropWarnings } from 'preact/debug';
import { forwardRef, createPortal } from 'preact/compat';
const h = createElement;
/** @jsx createElement */
describe('debug compat', () => {
let scratch;
let root;
let errors = [];
let warnings = [];
beforeEach(() => {
errors = [];
warnings = [];
scratch = setupScratch();
sinon.stub(console, 'error').callsFake(e => errors.push(e));
sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
root = document.createElement('div');
document.body.appendChild(root);
});
afterEach(() => {
/** @type {*} */
console.error.restore();
console.warn.restore();
teardown(scratch);
document.body.removeChild(root);
});
describe('portals', () => {
it('should not throw an invalid render argument for a portal.', () => {
function Foo(props) {
return
{createPortal(props.children, root)}
;
}
expect(() => render(foobar, scratch)).not.to.throw();
});
});
describe('PropTypes', () => {
beforeEach(() => {
resetPropWarnings();
});
it('should not fail if ref is passed to comp wrapped in forwardRef', () => {
// This test ensures compat with airbnb/prop-types-exact, mui exact prop types util, etc.
const Foo = forwardRef(function Foo(props, ref) {
return
{props.text}
;
});
Foo.propTypes = {
text: PropTypes.string.isRequired,
ref(props) {
if ('ref' in props) {
throw new Error(
'ref should not be passed to prop-types valiation!'
);
}
}
};
const ref = createRef();
render(, scratch);
expect(console.error).not.been.called;
expect(ref.current).to.not.be.undefined;
});
});
});
preact-10.29.2/debug/test/browser/debug-hooks.test.jsx 0000664 0000000 0000000 00000004666 15202310201 0022604 0 ustar 00root root 0000000 0000000 import { createElement, render, Component } from 'preact';
import { useState, useEffect } from 'preact/hooks';
import 'preact/debug';
import { act } from 'preact/test-utils';
import { setupScratch, teardown } from '../../../test/_util/helpers';
/** @jsx createElement */
describe('debug with hooks', () => {
let scratch;
let errors = [];
let warnings = [];
beforeEach(() => {
errors = [];
warnings = [];
scratch = setupScratch();
sinon.stub(console, 'error').callsFake(e => errors.push(e));
sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
});
afterEach(() => {
console.error.restore();
console.warn.restore();
teardown(scratch);
});
it('should throw an error when using a hook outside a render', () => {
class Foo extends Component {
componentWillMount() {
useState();
}
render() {
return this.props.children;
}
}
class App extends Component {
render() {
return
test
;
}
}
const fn = () =>
act(() =>
render(
,
scratch
)
);
expect(fn).to.throw(/Hook can only be invoked from render/);
});
it('should throw an error when invoked outside of a component', () => {
function foo() {
useEffect(() => {}); // Pretend to use a hook
return
test
;
}
const fn = () =>
act(() => {
render(foo(), scratch);
});
expect(fn).to.throw(/Hook can only be invoked from render/);
});
it('should throw an error when invoked outside of a component before render', () => {
function Foo(props) {
useEffect(() => {}); // Pretend to use a hook
return props.children;
}
const fn = () =>
act(() => {
useState();
render(Hello!, scratch);
});
expect(fn).to.throw(/Hook can only be invoked from render/);
});
it('should throw an error when invoked outside of a component after render', () => {
function Foo(props) {
useEffect(() => {}); // Pretend to use a hook
return props.children;
}
const fn = () =>
act(() => {
render(Hello!, scratch);
useState();
});
expect(fn).to.throw(/Hook can only be invoked from render/);
});
it('should throw an error when invoked inside an effect callback', () => {
function Foo(props) {
useEffect(() => {
useState();
});
return props.children;
}
const fn = () =>
act(() => {
render(Hello!, scratch);
});
expect(fn).to.throw(/Hook can only be invoked from render/);
});
});
preact-10.29.2/debug/test/browser/debug-suspense.test.jsx 0000664 0000000 0000000 00000011525 15202310201 0023316 0 ustar 00root root 0000000 0000000 import { createElement, render, lazy, Suspense } from 'preact/compat';
import 'preact/debug';
import { setupRerender } from 'preact/test-utils';
import {
setupScratch,
teardown,
serializeHtml
} from '../../../test/_util/helpers';
/** @jsx createElement */
describe('debug with suspense', () => {
/** @type {HTMLDivElement} */
let scratch;
let rerender;
let errors = [];
let warnings = [];
beforeEach(() => {
errors = [];
warnings = [];
scratch = setupScratch();
rerender = setupRerender();
sinon.stub(console, 'error').callsFake(e => errors.push(e));
sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
});
afterEach(() => {
console.error.restore();
console.warn.restore();
teardown(scratch);
});
it('should throw on missing ', () => {
function Foo() {
throw Promise.resolve();
}
expect(() => render(, scratch)).to.throw;
});
it('should throw an error when using lazy and missing Suspense', () => {
const Foo = () =>
;
}
}
render(, scratch);
expect(console.warn).to.be.calledOnce;
expect(console.warn.args[0]).to.match(/no-op/);
});
it('should warn when calling forceUpdate on an unmounted Component', () => {
let forceUpdate;
class Foo extends Component {
constructor(props) {
super(props);
forceUpdate = () => this.forceUpdate();
}
render() {
return
foo
;
}
}
render(, scratch);
forceUpdate();
expect(console.warn).to.not.be.called;
render(null, scratch);
forceUpdate();
expect(console.warn).to.be.calledOnce;
expect(console.warn.args[0]).to.match(/no-op/);
});
it('should print an error when child is a plain object', () => {
let fn = () => render(
{{}}
, scratch);
expect(fn).to.throw(/not valid/);
});
it('should print an error on invalid refs', () => {
let fn = () => render(, scratch);
expect(fn).to.throw(/createRef/);
});
it('should not print for null as a handler', () => {
let fn = () => render(, scratch);
expect(fn).not.to.throw();
});
it('should not print for undefined as a handler', () => {
let fn = () => render(, scratch);
expect(fn).not.to.throw();
});
it('should not print for attributes starting with on for Components', () => {
const Comp = () =>
online
;
let fn = () => render(, scratch);
expect(fn).not.to.throw();
});
it('should print an error on invalid handler', () => {
let fn = () => render(, scratch);
expect(fn).to.throw(/"onclick" property should be a function/);
});
it('should NOT print an error on valid refs', () => {
let noop = () => {};
render(, scratch);
let ref = createRef();
render(, scratch);
expect(console.error).to.not.be.called;
});
it('throws an error if a component rerenders too many times', () => {
let rerenderCount = 0;
function TestComponent({ loop = false }) {
const [count, setCount] = useState(0);
if (loop) {
setCount(count + 1);
}
if (count > 30) {
expect.fail(
'Repeated rerenders did not cause the expected error. This test is failing.'
);
}
rerenderCount += 1;
return ;
}
expect(() => {
render(
,
scratch
);
}).to.throw(/Too many re-renders/);
// 1 for first TestComponent + 24 for second TestComponent
expect(rerenderCount).to.equal(25);
});
it('does not throw an error if a component renders many times in different cycles', () => {
let set;
function TestComponent() {
const [count, setCount] = useState(0);
set = () => setCount(count + 1);
return
{count}
;
}
render(, scratch);
for (let i = 0; i < 30; i++) {
set();
rerender();
}
expect(scratch.innerHTML).to.equal('
;
it('should print an error on duplicate keys with DOM nodes', () => {
render(
,
scratch
);
expect(console.error).to.be.calledOnce;
});
it('should allow distinct object keys', () => {
const A = { is: 'A' };
const B = { is: 'B' };
render(
,
scratch
);
expect(console.error).not.to.be.called;
});
it('should print an error for duplicate object keys', () => {
const A = { is: 'A' };
render(
,
scratch
);
expect(console.error).to.be.calledOnce;
});
it('should print an error on duplicate keys with Components', () => {
function App() {
return (
abdd
);
}
render(, scratch);
expect(console.error).to.be.calledOnce;
});
it('should print an error on duplicate keys with Fragments', () => {
function App() {
return (
ab
{/* Should be okay to duplicate keys since these are inside a Fragment */}
cdef
, scratch);
expect(console.error).to.not.be.called;
});
});
describe('paragraph nesting', () => {
it('should not warn a regular text paragraph', () => {
const Paragraph = () =>
Hello world
;
render(, scratch);
expect(console.error).to.not.be.called;
});
it('should not crash for an empty pragraph', () => {
const Paragraph = () => ;
render(, scratch);
expect(console.error).to.not.be.called;
});
it('should warn for nesting illegal dom-nodes under a paragraph', () => {
const Paragraph = () => (
Hello world
);
render(, scratch);
expect(console.error).to.be.calledOnce;
});
it('should warn for nesting illegal dom-nodes under a paragraph with a parent', () => {
const Paragraph = () => (
Hello world
);
render(, scratch);
expect(console.error).to.be.calledOnce;
});
it('should warn for nesting illegal dom-nodes under a paragraph as func', () => {
const Title = ({ children }) =>
{children}
;
const Paragraph = () => (
Hello world
);
render(, scratch);
expect(console.error).to.be.calledOnce;
});
it('should not warn for nesting span under a paragraph', () => {
const Paragraph = () => (
Hello world
);
render(, scratch);
expect(console.error).to.not.be.called;
});
});
describe('button nesting', () => {
it('should not warn on a regular button', () => {
const Button = () => ;
render(, scratch);
expect(console.error).to.not.be.called;
});
it('should warn for nesting illegal dom-nodes under a button', () => {
const Button = () => (
);
render(, scratch);
expect(console.error).to.be.calledOnce;
});
it('should warn for nesting illegal dom-nodes under a button as func', () => {
const ButtonChild = ({ children }) => {children};
const Button = () => (
Hello world
);
render(, scratch);
expect(console.error).to.be.calledOnce;
});
it('should not warn for nesting non-interactive content under a button', () => {
const Button = () => (
Hello World
);
render(, scratch);
expect(console.error).to.not.be.called;
});
});
describe('anchor nesting', () => {
it('should not warn a regular anchor', () => {
const Anchor = () => Hello world;
render(, scratch);
expect(console.error).to.not.be.called;
});
it('should warn for nesting illegal dom-nodes under an anchor', () => {
const Anchor = () => (
Hello world
);
render(, scratch);
expect(console.error).to.be.calledOnce;
});
it('should warn for nesting illegal dom-nodes under an anchor as func', () => {
const AnchorChild = ({ children }) => {children};
const Anchor = () => (
Hello world
);
render(, scratch);
expect(console.error).to.be.calledOnce;
});
it('should not warn for nesting non-interactive content under an anchor', () => {
const Anchor = () => (
Hello World
);
render(, scratch);
expect(console.error).to.not.be.called;
});
});
describe('Hydration mismatches', () => {
it('Should warn us for a node mismatch', () => {
scratch.innerHTML = '
foo/div>';
const App = () => (
foo
);
hydrate(, scratch);
expect(console.error).to.be.calledOnce;
expect(console.error).to.be.calledOnceWith(
sinon.match(/Expected a DOM node of type "p" but found "span"/)
);
});
it('Should not warn for a text-node mismatch', () => {
scratch.innerHTML = '
foo bar baz/div>';
const App = () => (
foo {'bar'} {'baz'}
);
hydrate(, scratch);
expect(console.error).to.not.be.called;
});
it('Should not warn for a well-formed tree', () => {
scratch.innerHTML = '
foobar
';
const App = () => (
foobar
);
hydrate(, scratch);
expect(console.error).to.not.be.called;
});
});
});
preact-10.29.2/debug/test/browser/fakeDevTools.js 0000664 0000000 0000000 00000000074 15202310201 0021602 0 ustar 00root root 0000000 0000000 window.__PREACT_DEVTOOLS__ = { attachPreact: sinon.spy() };
preact-10.29.2/debug/test/browser/prop-types.test.js 0000664 0000000 0000000 00000006217 15202310201 0022321 0 ustar 00root root 0000000 0000000 import { createElement, render } from 'preact';
import {
setupScratch,
teardown,
serializeHtml
} from '../../../test/_util/helpers';
import './fakeDevTools';
import { resetPropWarnings } from 'preact/debug';
import * as PropTypes from 'prop-types';
import { jsxDEV as jsxDev } from 'preact/jsx-runtime';
describe('PropTypes', () => {
/** @type {HTMLDivElement} */
let scratch;
let errors = [];
let warnings = [];
beforeEach(() => {
errors = [];
warnings = [];
scratch = setupScratch();
sinon.stub(console, 'error').callsFake(e => errors.push(e));
sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
});
afterEach(() => {
/** @type {*} */
console.error.restore();
console.warn.restore();
teardown(scratch);
});
beforeEach(() => {
resetPropWarnings();
});
it("should fail if props don't match prop-types", () => {
function Foo(props) {
return jsxDev('h1', { children: props.text });
}
Foo.propTypes = {
text: PropTypes.string.isRequired
};
render(
jsxDev(
Foo,
{ text: 123 },
null,
// @ts-ignore
false,
// @ts-ignore
{ fileName: './debug/test/browser/debug.test.js', lineNumber: 41 },
// @ts-ignore
'self'
),
scratch
);
expect(console.error).to.be.calledOnce;
// The message here may change when the "prop-types" library is updated,
// but we check it exactly to make sure all parameters were supplied
// correctly.
expect(console.error).to.have.been.calledOnceWith(
sinon.match(
/^Failed prop type: Invalid prop `text` of type `number` supplied to `Foo`, expected `string`\.\n {2}in Foo \(at (.*)[/\\]debug[/\\]test[/\\]browser[/\\]debug\.test\.js:[0-9]+\)$/m
)
);
});
it('should only log a given prop type error once', () => {
function Foo(props) {
return jsxDev('h1', { children: props.text });
}
Foo.propTypes = {
text: PropTypes.string.isRequired,
count: PropTypes.number
};
// Trigger the same error twice. The error should only be logged
// once.
render(jsxDev(Foo, { text: 123 }), scratch);
render(jsxDev(Foo, { text: 123 }), scratch);
expect(console.error).to.be.calledOnce;
// Trigger a different error. This should result in a new log
// message.
console.error.resetHistory();
render(jsxDev(Foo, { text: 'ok', count: '123' }), scratch);
expect(console.error).to.be.calledOnce;
});
it('should render with error logged when validator gets signal and throws exception', () => {
function Baz(props) {
return jsxDev('h1', { children: props.unhappy });
}
Baz.propTypes = {
unhappy: function alwaysThrows(obj, key) {
if (obj[key] === 'signal') throw Error('got prop');
}
};
render(jsxDev(Baz, { unhappy: 'signal' }), scratch);
expect(console.error).to.be.calledOnce;
expect(errors[0].includes('got prop')).to.equal(true);
expect(serializeHtml(scratch)).to.equal('
signal
');
});
it('should not print to console when types are correct', () => {
function Bar(props) {
return jsxDev('h1', { children: props.text });
}
Bar.propTypes = {
text: PropTypes.string.isRequired
};
render(jsxDev(Bar, { text: 'foo' }), scratch);
expect(console.error).to.not.be.called;
});
});
preact-10.29.2/debug/test/browser/serializeVNode.test.jsx 0000664 0000000 0000000 00000003270 15202310201 0023306 0 ustar 00root root 0000000 0000000 import { createElement, Component } from 'preact';
import { serializeVNode } from '../../src/debug';
/** @jsx createElement */
describe('serializeVNode', () => {
it("should prefer a function component's displayName", () => {
function Foo() {
return ;
}
Foo.displayName = 'Bar';
expect(serializeVNode()).to.equal('');
});
it("should prefer a class component's displayName", () => {
class Bar extends Component {
render() {
return ;
}
}
Bar.displayName = 'Foo';
expect(serializeVNode()).to.equal('');
});
it('should serialize vnodes without children', () => {
expect(serializeVNode( )).to.equal(' ');
});
it('should serialize vnodes with children', () => {
expect(serializeVNode(
Hello World
)).to.equal('
..
');
});
it('should serialize components', () => {
function Foo() {
return ;
}
expect(serializeVNode()).to.equal('');
});
it('should serialize props', () => {
expect(serializeVNode()).to.equal('');
// Ensure that we have a predictable function name. Our test runner
// creates an all inclusive bundle per file and the identifier
// "noop" may have already been used.
// eslint-disable-next-line func-style
let noop = function noopFn() {};
expect(serializeVNode()).to.equal(
''
);
function Foo(props) {
return props.foo;
}
expect(serializeVNode()).to.equal(
''
);
expect(serializeVNode()).to.equal(
''
);
});
});
preact-10.29.2/debug/test/browser/validateHookArgs.test.jsx 0000664 0000000 0000000 00000004135 15202310201 0023613 0 ustar 00root root 0000000 0000000 import { createElement, render, createRef } from 'preact';
import {
useState,
useEffect,
useLayoutEffect,
useCallback,
useMemo,
useImperativeHandle
} from 'preact/hooks';
import { setupRerender } from 'preact/test-utils';
import { setupScratch, teardown } from '../../../test/_util/helpers';
import 'preact/debug';
/** @jsx createElement */
describe('Hook argument validation', () => {
/**
* @param {string} name
* @param {(arg: number) => void} hook
*/
function validateHook(name, hook) {
const TestComponent = ({ initialValue }) => {
const [value, setValue] = useState(initialValue);
hook(value);
return (
setValue(NaN)}>
Set to NaN
);
};
it(`should error if ${name} is mounted with NaN as an argument`, async () => {
render(, scratch);
expect(console.warn).to.be.calledOnce;
expect(console.warn.args[0]).to.match(
/Hooks should not be called with NaN in the dependency array/
);
});
it(`should error if ${name} is updated with NaN as an argument`, async () => {
render(, scratch);
scratch.querySelector('button').click();
rerender();
expect(console.warn).to.be.calledOnce;
expect(console.warn.args[0]).to.match(
/Hooks should not be called with NaN in the dependency array/
);
});
}
/** @type {HTMLElement} */
let scratch;
/** @type {() => void} */
let rerender;
let warnings = [];
beforeEach(() => {
scratch = setupScratch();
rerender = setupRerender();
warnings = [];
sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
});
afterEach(() => {
teardown(scratch);
console.warn.restore();
});
validateHook('useEffect', arg => useEffect(() => {}, [arg]));
validateHook('useLayoutEffect', arg => useLayoutEffect(() => {}, [arg]));
validateHook('useCallback', arg => useCallback(() => {}, [arg]));
validateHook('useMemo', arg => useMemo(() => {}, [arg]));
const ref = createRef();
validateHook('useImperativeHandle', arg => {
useImperativeHandle(ref, () => undefined, [arg]);
});
});
preact-10.29.2/demo/ 0000775 0000000 0000000 00000000000 15202310201 0014051 5 ustar 00root root 0000000 0000000 preact-10.29.2/demo/contenteditable.jsx 0000664 0000000 0000000 00000001011 15202310201 0017734 0 ustar 00root root 0000000 0000000 import { useState } from 'preact/hooks';
export default function Contenteditable() {
const [value, setValue] = useState("Hey there I'm editable!");
return (
setValue('')}>Clear!
setValue(e.currentTarget.innerHTML)}
dangerouslySetInnerHTML={{ __html: value }}
/>
);
}
}
preact-10.29.2/demo/spiral.jsx 0000664 0000000 0000000 00000006274 15202310201 0016102 0 ustar 00root root 0000000 0000000 import { createElement, Component } from 'preact';
const COUNT = 500;
const LOOPS = 6;
// Component.debounce = requestAnimationFrame;
export default class Spiral extends Component {
state = { x: 0, y: 0, big: false, counter: 0 };
handleClick = e => {
console.log('click');
};
increment = () => {
if (this.stop) return;
// this.setState({ counter: this.state.counter + 1 }, this.increment);
this.setState({ counter: this.state.counter + 1 });
// this.forceUpdate();
requestAnimationFrame(this.increment);
};
setMouse({ pageX: x, pageY: y }) {
this.setState({ x, y });
return false;
}
setBig(big) {
this.setState({ big });
}
componentDidMount() {
console.log('mount');
// let touch = navigator.maxTouchPoints > 1;
let touch = false;
// set mouse position state on move:
addEventListener(touch ? 'touchmove' : 'mousemove', e => {
this.setMouse(e.touches ? e.touches[0] : e);
});
// holding the mouse down enables big mode:
addEventListener(touch ? 'touchstart' : 'mousedown', e => {
this.setBig(true);
e.preventDefault();
});
addEventListener(touch ? 'touchend' : 'mouseup', e => this.setBig(false));
requestAnimationFrame(this.increment);
}
componentWillUnmount() {
console.log('unmount');
this.stop = true;
}
// componentDidUpdate() {
// // invoking setState() in componentDidUpdate() creates an animation loop:
// this.increment();
// }
// builds and returns a brand new DOM (every time)
render(props, { x, y, big, counter }) {
let max =
COUNT +
Math.round(Math.sin((counter / 90) * 2 * Math.PI) * COUNT * 0.5),
cursors = [];
// the advantage of JSX is that you can use the entirety of JS to "template":
for (let i = max; i--; ) {
let f = (i / max) * LOOPS,
θ = f * 2 * Math.PI,
m = 20 + i * 2,
hue = (f * 255 + counter * 10) % 255;
cursors[i] = (
);
}
return (
{cursors}
);
}
}
/** Represents a single coloured dot. */
class Cursor extends Component {
// get shared/pooled class object
getClass(big, label) {
let cl = 'cursor';
if (big) cl += ' big';
if (label) cl += ' label';
return cl;
}
// skip any pointless re-renders
shouldComponentUpdate(props) {
for (let i in props)
if (i !== 'children' && props[i] !== this.props[i]) return true;
return false;
}
// first argument is "props", the attributes passed to
render({ x, y, label, color, big }) {
let inner = null;
if (label)
inner = (
{x},{y}
);
return (
{inner}
);
}
}
// Addendum: disable dragging on mobile
addEventListener('touchstart', e => (e.preventDefault(), false));
preact-10.29.2/demo/stateOrderBug.jsx 0000664 0000000 0000000 00000003017 15202310201 0017352 0 ustar 00root root 0000000 0000000 import htm from 'htm';
import { h } from 'preact';
import { useState, useCallback } from 'preact/hooks';
const html = htm.bind(h);
// configuration used to show behavior vs. workaround
let childFirst = true;
const Config = () => html`
`;
const Child = ({ items, setItems }) => {
let [pendingId, setPendingId] = useState(null);
if (!pendingId) {
setPendingId((pendingId = Math.random().toFixed(20).slice(2)));
}
const onInput = useCallback(
evt => {
let val = evt.target.value,
_items = [...items, { _id: pendingId, val }];
if (childFirst) {
setPendingId(null);
setItems(_items);
} else {
setItems(_items);
setPendingId(null);
}
},
[childFirst, setPendingId, setItems, items, pendingId]
);
return html`
${items.map(
(item, idx) => html`
{
let val = evt.target.value,
_items = [...items];
_items.splice(idx, 1, { ...item, val });
setItems(_items);
}}
/>
`
)}
);
}
preact-10.29.2/devtools/ 0000775 0000000 0000000 00000000000 15202310201 0014764 5 ustar 00root root 0000000 0000000 preact-10.29.2/devtools/LICENSE 0000664 0000000 0000000 00000002077 15202310201 0015777 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2015-present Jason Miller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
preact-10.29.2/devtools/mangle.json 0000664 0000000 0000000 00000001254 15202310201 0017124 0 ustar 00root root 0000000 0000000 {
"help": {
"what is this file?": "It controls protected/private property mangling so that minified builds have consistent property names.",
"why are there duplicate minified properties?": "Most properties are only used on one type of objects, so they can have the same name since they will never collide. Doing this reduces size."
},
"minify": {
"mangle": {
"properties": {
"regex": "^_[^_]",
"reserved": [
"__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
"__REACT_DEVTOOLS_GLOBAL_HOOK__",
"__PREACT_DEVTOOLS__",
"_renderers",
"__source",
"__self"
]
}
}
}
}
preact-10.29.2/devtools/package.json 0000664 0000000 0000000 00000001165 15202310201 0017255 0 ustar 00root root 0000000 0000000 {
"name": "preact-devtools",
"amdName": "preactDevtools",
"version": "1.0.0",
"private": true,
"description": "Preact bridge for Preact devtools",
"main": "dist/devtools.js",
"module": "dist/devtools.module.js",
"umd:main": "dist/devtools.umd.js",
"source": "src/index.js",
"license": "MIT",
"types": "src/index.d.ts",
"peerDependencies": {
"preact": "^10.0.0"
},
"exports": {
".": {
"types": "./src/index.d.ts",
"browser": "./dist/devtools.module.js",
"umd": "./dist/devtools.umd.js",
"import": "./dist/devtools.mjs",
"require": "./dist/devtools.js"
}
}
}
preact-10.29.2/devtools/src/ 0000775 0000000 0000000 00000000000 15202310201 0015553 5 ustar 00root root 0000000 0000000 preact-10.29.2/devtools/src/devtools.js 0000664 0000000 0000000 00000000652 15202310201 0017753 0 ustar 00root root 0000000 0000000 import { Component, Fragment, options } from 'preact';
export function initDevTools() {
const globalVar =
typeof globalThis !== 'undefined'
? globalThis
: typeof window !== 'undefined'
? window
: undefined;
if (
globalVar !== null &&
globalVar !== undefined &&
globalVar.__PREACT_DEVTOOLS__
) {
globalVar.__PREACT_DEVTOOLS__.attachPreact('10.29.2', options, {
Fragment,
Component
});
}
}
preact-10.29.2/devtools/src/index.d.ts 0000664 0000000 0000000 00000000351 15202310201 0017453 0 ustar 00root root 0000000 0000000 /**
* Customize the displayed name of a useState, useReducer or useRef hook
* in the devtools panel.
*
* @param value Wrapped native hook.
* @param name Custom name
*/
export function addHookName(value: T, name: string): T;
preact-10.29.2/devtools/src/index.js 0000664 0000000 0000000 00000000520 15202310201 0017215 0 ustar 00root root 0000000 0000000 import { options } from 'preact';
import { initDevTools } from './devtools';
initDevTools();
/**
* Display a custom label for a custom hook for the devtools panel
* @type {(value: T, name: string) => T}
*/
export function addHookName(value, name) {
if (options._addHookName) {
options._addHookName(name);
}
return value;
}
preact-10.29.2/devtools/test/ 0000775 0000000 0000000 00000000000 15202310201 0015743 5 ustar 00root root 0000000 0000000 preact-10.29.2/devtools/test/browser/ 0000775 0000000 0000000 00000000000 15202310201 0017426 5 ustar 00root root 0000000 0000000 preact-10.29.2/devtools/test/browser/addHookName.test.jsx 0000664 0000000 0000000 00000002065 15202310201 0023307 0 ustar 00root root 0000000 0000000 import { createElement, render, options } from 'preact';
import { setupScratch, teardown } from '../../../test/_util/helpers';
import { useState } from 'preact/hooks';
import { addHookName } from 'preact/devtools';
/** @jsx createElement */
describe('addHookName', () => {
/** @type {HTMLDivElement} */
let scratch;
beforeEach(() => {
scratch = setupScratch();
});
afterEach(() => {
teardown(scratch);
delete options._addHookName;
});
it('should do nothing when no options hook is present', () => {
function useFoo() {
return addHookName(useState(0), 'foo');
}
function App() {
let [v] = useFoo();
return
{v}
;
}
expect(() => render(, scratch)).to.not.throw();
});
it('should call options hook with value', () => {
let spy = (options._addHookName = sinon.spy());
function useFoo() {
return addHookName(useState(0), 'foo');
}
function App() {
let [v] = useFoo();
return