From e02dd1927d93d721fa056b8ff1826f566ff93a15 Mon Sep 17 00:00:00 2001 From: Ivan Kudinov Date: Tue, 1 Sep 2026 15:02:25 +0300 Subject: [PATCH] CCS-114325 Fix copy restrictions on mobile --- .github/workflows/npm-publish.yml | 27 ++++++++++++------ .npmrc | 1 + package.json | 8 ++++-- src/lib/helpers/helpers.ts | 46 +++++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 13 deletions(-) create mode 100644 .npmrc diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index b75863b..0aad90c 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -5,20 +5,29 @@ on: types: [created] workflow_dispatch: +permissions: + contents: read + id-token: write # Required for npm provenance (Trusted Publishing) + jobs: build-and-publish: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 - - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 24 + cache: 'yarn' registry-url: https://registry.npmjs.org/ + + - name: Install dependencies + run: yarn install --frozen-lockfile + - name: Build package - run: yarn install && yarn build - - name: Publish package on NPM - run: npm publish - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + run: yarn build + + - name: Publish package on NPM (Trusted Publishing) + run: npm publish --provenance --access public --tag $(node -p "const v=require('./package.json').version;v.includes('-')?v.match(/-(.+?)\./)[1]:'latest'") \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..5660f81 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmjs.org/ \ No newline at end of file diff --git a/package.json b/package.json index 8eda1fc..31f6311 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@expressms/smartapp-sdk", - "version": "1.14.0", + "version": "1.15.0-alpha.2", "description": "Smartapp SDK", "main": "build/main/index.js", "typings": "build/main/index.d.ts", @@ -16,13 +16,17 @@ }, "repository": { "type": "git", - "url": "git@github.com:ExpressApp/smartapp-sdk.git" + "url": "git+https://github.com/ExpressApp/smartapp-sdk.git" }, "engines": { "node": ">=10" }, "author": "", "license": "ISC", + "publishConfig": { + "access": "public", + "provenance": true + }, "devDependencies": { "@rollup/plugin-commonjs": "^17.1.0", "@rollup/plugin-json": "^4.1.0", diff --git a/src/lib/helpers/helpers.ts b/src/lib/helpers/helpers.ts index 2bce52c..8643fb1 100644 --- a/src/lib/helpers/helpers.ts +++ b/src/lib/helpers/helpers.ts @@ -1,3 +1,5 @@ +const COPY_RESTRICION_STYLE_ID = 'native-copy-restriction' + export const useQuery = () => { const urlSearchParams = new URLSearchParams(window.location.search) return Object.fromEntries(urlSearchParams.entries()) @@ -5,10 +7,50 @@ export const useQuery = () => { const noop = (event: Event): boolean => { event.preventDefault() + event.stopImmediatePropagation() return false } +const preventSelection = (event: Event): void => { + const isInput = + event.target instanceof Element && event.target.closest('input, textarea, [contenteditable="true"]') !== null + + if (!isInput) noop(event) +} + +const addCopyRestrictionStyles = (): void => { + if (document.getElementById(COPY_RESTRICION_STYLE_ID)) return + + const style = document.createElement('style') + style.id = COPY_RESTRICION_STYLE_ID + style.textContent = ` + html, + body, + body * { + -webkit-user-select: none !important; + user-select: none !important; + -webkit-touch-callout: none !important; + } + + body input, + body textarea, + body [contenteditable="true"], + body [contenteditable="true"] * { + -webkit-user-select: text !important; + user-select: text !important; + -webkit-touch-callout: default !important; + } + ` + + const styleRoot = document.head || document.documentElement + styleRoot.appendChild(style) +} + export const disableCopy = () => { - document.addEventListener('contextmenu', noop); - document.addEventListener('copy', noop) + document.addEventListener('contextmenu', noop, true) + document.addEventListener('copy', noop, true) + document.addEventListener('cut', noop, true) + document.addEventListener('selectstart', preventSelection, true) + + addCopyRestrictionStyles() }